Skip to content
This page has been auto-translated and may contain errors.View in English

你的第一个仓库

docs.scrimba.com

通常有两种方式会让你来到这里。一种是你已经有一个项目文件夹,比如你一直在本地构建的 weather-app,现在想让 Git 开始记录它的历史。另一种是别人已经建立了项目,它存在于 GitHub 上,你想在你的机器上获得一份工作副本。两种情况都从三个简单命令开始,到本章结束时,你将真正使用过所有三个命令。不过首先,有一个只需十秒的检查:确认你的机器上是否安装了 Git。

你安装了 Git 吗?

本手册中的一切都在终端中进行,所以第一步是打开一个。**终端**是一个应用程序,你可以在其中输入文本命令,程序用文本回复。它已经在你的计算机上了:

  • macOS: 应用程序叫做终端。按 Cmd+Space,输入"terminal",然后按 Enter。
  • Windows: 现在打开 PowerShell(在开始菜单中搜索"powershell")。下面安装的 Git 还会添加 Git Bash,一个为此专门构建的终端,两者都可以运行相同的 Git 命令。
  • Linux: 查找名为 Terminal 或 Console 的应用程序;在许多发行版上,Ctrl+Alt+T 可以打开它。

Git 本身是一个命令行程序:它没有自己的窗口,你通过输入以 git 开头的命令来使用它,并阅读它打印的内容。这也是阅读本手册中每个代码块的方式:以 $ 开头的行是你要输入的命令(不包括 $ 本身),下面的行是 Git 的回复。

所以,进行检查。在你的终端中输入以下内容并按 Enter:

bash
$ git --version
git version 2.45.1

返回的版本号意味着 Git 已安装,你已准备好。 你的版本号可能与这个不同,这是可以的。如果你看到"command not found"或"git is not recognized",Git 还没有安装在你的机器上,安装它是一次性的工作:

  • macOS: 运行 git --version 通常会打开一个对话框,提供安装 Apple 的命令行工具。接受它,macOS 将为你安装 Git。
  • Windows:git-scm.com/downloads 下载 Git for Windows 并运行安装程序。默认设置都是合理的选择,它会在安装过程中添加 Git Bash。
  • Linux: 使用你发行版的包管理器安装 git 包,例如在 Ubuntu 和 Debian 上使用 sudo apt install git

安装完成后,关闭你的终端,打开一个新的,然后再次运行 git --version。返回的版本号意味着你已完成一次性设置;本手册的其余部分不需要任何安装。

版本号的重要性比看起来要大一点。本手册使用现代动词 git switchgit restore,它们在 2019 年 Git 2.23 中出现,所以一台装有非常旧的预装 Git 的机器可能会在正确的示例上遇到"not a git command"。过去几年的任何 Git 都有它们;如果你的版本早于 2.23,请从上面列出的相同位置更新它。

你还会遇到图形化 Git 工具:GitHub Desktop、VS Code 中的 Git 面板、大多数编辑器中的内置支持。所有这些都是运行相同 Git 程序的前端。首先学习命令会在那里也得到回报,因为这些工具中的每个按钮都对应一个你已经理解的命令。

Git 是一个单一的自包含程序,不是一个服务。没有什么在后台运行,没有什么监视你的文件夹,也没有账户可以登录:每个命令都会启动、读取或写入仓库内的文件、打印其答案并退出。这也是为什么所有这些都离线工作。运行 which git(在 Windows 上运行 where git)可以看到程序在磁盘上的确切位置。

值得知道的一个平台怪癖:在 macOS 上,Apple 使用其自己构建的 Git,通常比 git-scm.com 上的最新版本晚一两个版本。对于本手册中的所有内容,以及日常工作中的几乎所有内容,这个差距都不重要。

Juno你安装了 Git 吗? Git 是一个程序,你可以通过在终端中输入命令来与之交互,git --version 告诉你它是否在你的机器上:版本号意味着你已准备好,"command not found"意味着从 git-scm.com 或你系统的安装程序安装它。你只需要执行这部分一次。设置是任何手册中最无趣的部分,所以做得很好!
Juno你安装了 Git 吗?git --version 用一行就能解决安装问题。任何相对较新的版本都可以,虽然本手册使用的 switchrestore 动词需要 Git 2.23 或更新版本,所以如果你的版本较旧,请更新。GitHub Desktop 等 GUI 工具在下面运行相同的程序,这意味着你在这里学到的一切都可以免费转移到它们。
Juno你安装了 Git 吗? Git 是一个本地程序,没有守护进程,也没有账户:它在你输入时运行,接触仓库中的文件,然后退出,这就是为什么它的每一部分都离线工作。which git 向你显示二进制文件。Apple 的捆绑构建比最新版本落后一两个版本,在十四年里,这个差距对我没有造成任何问题。

将文件夹转变为仓库

打开一个终端,使用 cd("change directory"的缩写)进入你的项目文件夹,然后运行一个命令 git init

bash
$ cd weather-app
$ git init
Initialized empty Git repository in /Users/mara/projects/weather-app/.git/

该文件夹现在是一个**仓库**:Git 监视的项目,准备在你工作时记录它的快照。git init 每次都做同样的事情。它查找一个隐藏的 .git 文件夹,如果它缺失,就创建一个,从那时起该文件夹就在 Git 的监视下。

新仓库的默认分支被命名为 main 如果你遇到较旧的教程、较旧的仓库或几年前录制的课程,你会看到 master 被用于完全相同的事情:它是同一第一个分支的较旧名称。本手册总是使用 main

什么是分支?

分支是你的提交所在的单独的历史线,main 是每个新仓库都从它开始的。分支涵盖创建和在它们之间切换。

git init 不在乎文件夹是否为空。在 weather-app 中运行它,其中 index.htmlsrc/ 文件夹已经存在,Git 从它所在的位置开始跟踪该项目;现有文件都不会改变。在同一仓库中第二次运行 git init 也是无害的。Git 注意到 .git 文件夹已经存在,并在原地重新初始化它,而不会触及你已有的任何历史,所以习惯性地再次运行它不会让你付出任何代价。

git init 只做一件事:创建 .git 文件夹,本章稍后会详细展开。关于仓库的一切,它的历史、它的设置、它的引用,从 init 创建它的那一刻起就存在于该文件夹中。你在项目中看到和编辑的文件是被跟踪的工作副本,.git 文件夹是仓库本身。

Juno将文件夹转变为仓库git init 将任何文件夹转变为 Git 仓库,准备好让 Git 开始跟踪它。在项目文件夹中运行一次,你就完成了,以后再运行也不会造成伤害。新仓库默认分支叫做 main,虽然你在野外找到的较旧仓库通常叫 master 以表示相同的东西。
Juno将文件夹转变为仓库git init 在空文件夹或已经填满文件的文件夹中都能工作,在你已经设置的仓库上再次运行它也不会造成损害,因为 Git 识别 .git 文件夹已经存在。默认分支名称是 main;在任何较旧的东西中预期 master
Juno将文件夹转变为仓库git init 只创建 .git 文件夹,这是实际的仓库。你的工作文件是该文件夹跟踪的内容的检出。保持你的工作文件和跟踪它们的 .git 文件夹之间的这种分割。

告诉 Git 你是谁

在你的第一次提交之前,Git 想知道是谁在进行提交。设置两个值一次,Git 会在你在这台机器上进行的每次提交中记住它们:

bash
$ git config --global user.name "陈玲"
$ git config --global user.email "[email protected]"

你创建的每一次提交都会用那个名称和电子邮件打上时间戳。跳过这一步,Git 会退回到从你的计算机用户名和主机名猜测的东西,所以你的提交会带有你从未选择过的身份。

在你的第一次提交之前设置你的名称和电子邮件。 先提交,然后再设置,这个错误会烤进该提交的历史中。更糟的是,一些主机(包括 GitHub)通过电子邮件将提交匹配到你的账户,所以在错误的地址或猜测的地址下进行的提交会显示为匿名陌生人的工作,而不是你的。

--global 标志设置一个**配置范围**:--global 应用于你机器上的所有地方,而 --local 仅应用于你运行它时所在的仓库。这让你可以分层设置。你的全局电子邮件默认覆盖每个仓库,一个特定仓库中的 --local 覆盖在那里优先,但在其他地方不优先,当工作项目需要与你的个人项目不同的地址时很有用:

bash
$ cd weather-app
$ git config --local user.email "[email protected]"
$ git config user.email
[email protected]

运行 git config user.email 而没有范围标志会读取实际适用于此处的值:如果你设置了本地值,就是本地值,否则就是全局值。

两个范围都是 Git 按固定顺序读取的文本文件。全局的位于 ~/.gitconfig;本地的位于仓库的 .git 文件夹中,在 .git/config。Git 首先读取本地设置,让它们覆盖全局设置,这就是整个分层机制,在你可以自己打开和阅读的纯文本文件中展开。

Juno告诉 Git 你是谁git config --global user.namegit config --global user.email 设置 Git 在你进行的每次提交上打上时间戳的名称和电子邮件。在你的第一次提交之前设置它们,因为在你设置电子邮件之前进行的提交会被归属于猜测的身份,像 GitHub 这样的主机可能根本不会将其与你的账户相连。执行一次,你机器上的每个仓库都会记住它。
Juno告诉 Git 你是谁--global 应用于你机器上的每个仓库,--local 仅为当前仓库覆盖它,对于将个人电子邮件与工作电子邮件分开很有用。当两者都设置时本地设置获胜,git config user.email 告诉你在给定的仓库中实际上是哪个值。
Juno告诉 Git 你是谁 配置范围是分层文本文件:全局位于 ~/.gitconfig,本地位于仓库内的 .git/config,当两个都设置值时本地获胜。跳过设置你的电子邮件,Git 会退回到由你的用户名和机器名构建的猜测身份,这就是为什么一个陌生名字下的走失提交几乎总是追溯到缺失的 user.email

使用 git clone 复制现有项目

有时项目已经存在于其他地方,你想在你的机器上获得一份工作副本。git clone 用一个命令就可以做到:

bash
$ git clone https://github.com/octocat/Hello-World.git
Cloning into 'Hello-World'...
remote: Enumerating objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Receiving objects: 100% (13/13), done.

Git 创建一个名为 Hello-World 的新文件夹,将项目的完整历史下载到其中,并将其文件放在文件夹中,以便你可以立即开始阅读或编辑。不需要单独的 git init 步骤。克隆作为下载的一部分为你设置仓库。

当项目已经存在于某个地方并且你想要一份连接的副本时,使用 git clone。当你从头开始一些尚不存在的新东西时,使用 git init。克隆还会连接回你克隆来源的地方,在名称 origin 下,init 单独永远不会这样做;这个连接是以后的章节用来发送和接收提交的。

克隆会下载项目的整个历史,它曾经有过的每一次提交,并在你的机器上填充整个 .git 文件夹,git init 会使其为空。一个有多年历史的项目克隆可能需要一点时间,正是这个原因,尽管你之后看到的看起来像最新文件的快照。

Juno使用 git clone 复制现有项目git clone <url> 下载某人的仓库,包括完整的历史,放入以项目命名的新文件夹。当项目已经存在于某个地方时使用它;当你从头开始时使用 git init。克隆完成后,你有一份完整的工作副本,准备好查看或添加。
Juno使用 git clone 复制现有项目 当项目已经存在于某个地方并且你想要一份连接的副本时克隆;当什么都不存在时初始化。克隆自动连接回你克隆来源的地方,在名称 origin 下,这是 init 单独永远不会设置的。
Juno使用 git clone 复制现有项目 克隆使用项目曾经有过的每一次提交重新创建整个 .git 文件夹。这包括完整的历史,这就是为什么一个较旧的项目可能需要一点时间来克隆,即使你之后只看到它的当前文件。

隐藏的 .git 文件夹内有什么

每个仓库,无论你是通过 git init 还是 git clone 到达的,在其根目录都有一个名为 .git 的隐藏文件夹。它默认是隐藏的,所以向终端询问完整的列表,使用 ls -als 列出文件夹的内容,-a 包括隐藏条目)以看到它与你的普通项目文件并排:

bash
$ ls -a
.  ..  .git  README.md  src

该文件夹是真正的仓库。它保存你进行的每一次提交、你的分支和来自上面部分的配置设置。删除 .git 文件夹,项目就会丧失其整个历史,变回 Git 不再跟踪的普通文件夹。项目中的一切其他东西都是 .git 保存的工作副本。

查看里面,你会发现一些可识别的部分:一个 config 文件(上面部分的本地设置)、一个 HEAD 文件和名为 objectsrefs 的文件夹。你不需要手动打开或编辑这些中的任何一个,但识别这些名称有助于当它们中的一个出现在错误消息或搜索结果中时。

这些名称中的一些是值得妥善知道的。objects 文件夹是仓库的**对象数据库**:你进行的每个文件版本和每一次提交,压缩和按内容本身而不是文件名存储。refs 文件夹保存你的分支,每个都是指向一个提交 id 的小文件。HEAD 是一个单一的文件,记录你当前检出的分支。config 是上面涵盖的本地设置文件。

这都不是你日常手动编辑的东西。看到你的整个历史作为普通文件存在,而不是隐藏在某个服务器上的某处,解释了为什么克隆会离线给你完整的历史,以及为什么删除 .git 不会整理任何东西:它会抹除项目曾经有过的每一次提交。

Juno隐藏的 .git 文件夹内有什么 每个仓库在其根目录都有一个隐藏的 .git 文件夹,该文件夹是真正的仓库:你的整个历史和它的设置都存在于那里。在项目中运行 ls -a 可以看到它,因为它默认是隐藏的。除非你真的想抹除项目的整个历史,否则永远不要删除它,因为删除它会将文件夹变回 Git 不再跟踪的普通文件夹。
Juno隐藏的 .git 文件夹内有什么.git 内,你会识别一个 config 文件(你的本地设置)、一个 HEAD 文件和 objectsrefs 文件夹。你不会日常手动接触这些,但这些名称会出现在错误消息和 Git 文档中。克隆会复制这整个文件夹,这就是为什么克隆到达时有完整的历史而不仅仅是最新的文件。
Juno隐藏的 .git 文件夹内有什么objects 是仓库的对象数据库,保存每个文件版本和每一次提交,按内容而不是文件名寻址。refs 保存你的分支作为指向提交 id 的普通文件,HEAD 记录你检出的分支。那里的任何东西都不需要手动编辑,但将其视为磁盘上的普通文件,这就是克隆给你完整离线历史的原因,以及删除 .git 抹除所有东西而不仅仅是清理的原因。

如果术语仓库和提交仍然感到模糊,什么是 Git 涵盖这些命令构建的心智模型,词汇表对本章中的每一个词汇都有简短的定义。一旦你的身份被设置,你有一个要使用的仓库,提交循环涵盖你从现在开始会不断使用的编辑、暂存和提交的日常循环。