git fetch 命令将提交、文件和引用从远程存储库下载到本地代码存储库中。如果您想看看其他人都在处理什么工作,您要做的就是获取。它与 svn update 很类似,因为它能让您看到中央历史记录的进度,但它并不会强迫您将变更实际合并到存储库中。Git 会将获取的内容与现有的本地内容隔离开来,绝对不会影响您的本地开发工作。所获取的内容必须通过 git checkout 命令进行显式签出。这使得获取成为了一种安全的方式,您可以先查看提交,然后再将其与本地存储库集成。

从远程代码存储库下载内容时,您可以使用 git pullgit fetch 命令来完成任务。您可以将 git fetch 视为这两个命令的“安全”版本。它会下载远程内容,但不会更新本地代码存储库的工作状态,从而使您的当前工作保持不变。git pull 是另一种更为激进的方法,它会为活动的本地分支下载远程内容,并立即执行 git merge 来为新的远程内容创建合并提交。如果您有正在处理的变更,这会导致冲突并启动合并冲突解决流程。

git fetch 如何处理远程分支

为了更好地了解 git fetch 的工作原理,让我们来讨论一下 Git 是如何组织和存储提交的。在后台,Git 将所有本地提交和远程提交都存储在存储库的 ./.git/objects 目录中。Git 通过使用分支引用,来使远程分支提交和本地分支提交保持完全独立。本地分支的引用存储在 ./.git/refs/heads/ 中。执行 git branch 命令将会输出本地分支引用的列表。以下是带有一些演示分支名称的 git branch 输出示例。

git branch
main
feature1
debug2

检查 /.git/refs/heads/ 目录的内容将会显示类似的输出。

ls ./.git/refs/heads/
main
feature1
debug2

远程分支就像本地分支一样,只是它们映射到别人存储库中的提交。远程分支以它们所属的远程为前缀,这样您就不会将它们与本地分支混淆了。像本地分支一样,Git 也有远程分支的引用。远程分支引用位于 ./.git/refs/remotes/ 目录中。下一个示例代码片段显示了您在获取远程代码存储库(为方便起见,将其命名为 remote-repo)后可能会看到的分支:

git branch -r
# origin/main
# origin/feature1
# origin/debug2
# remote-repo/main
# remote-repo/other-feature

此输出显示了我们之前检查过的本地分支,但现在显示它们的前缀是 origin/。此外,我们现在还看到以 remote-repo 为前缀的远程分支。您可以像签出本地分支一样签出远程分支,但是这会使您处于游离的 HEAD 状态(就像签出旧的提交一样)。您可以将它们视为只读分支。要查看您的远程分支,只需将 -r 标记传递给 git branch 命令即可。

您可以使用常用的 git checkoutgit log 命令来检查远程分支。如果您批准远程分支所包含的变更,就可以使用常规的 git merge 将其合并到本地分支中。因此,与 SVN 不同,将本地存储库与远程存储库同步实际上是一个包含两个步骤的过程:获取,然后合并。git pull 命令是完成此流程的一种快捷方式。

git fetch 命令和选项

git fetch <remote>

从存储库中获取所有分支。这还将从其他存储库下载所有必需的提交和文件。

git fetch <remote> <branch>

与上面的命令相同,但仅获取指定的分支。

git fetch --all

一次大动作,获取所有已注册的远程及其分支:

git fetch --dry-run

--dry-run 选项将执行命令的演示运行。它将输出一些它在获取过程中将执行的操作的示例,但不会应用它们。

git fetch 示例

使用 git fetch 获取远程分支

以下示例将演示如何获取远程分支并将本地工作状态更新为远程内容。在此示例中,假设存在一个中央源代码存储库,而且我们已经使用 git clone 命令从中克隆了本地存储库。让我们还假设另外一个名为 coworkers_repo 的远程存储库,其中包含我们将对其进行配置和获取的 feature_branch。确定了这些假设之后,让我们继续演示示例。

首先,我们需要使用 git remote 命令配置远程代码存储库。

git remote add coworkers_repo git@bitbucket.org:coworker/coworkers_repo.git

在这里,我们使用同事的代码存储库 URL 创建了对该代码存储库的引用。现在,我们将该远程名称传递给 git fetch 以下载内容。

git fetch coworkers_repo coworkers/feature_branch
fetching coworkers/feature_branch

现在,我们在本地有了 coworkers/feature_branch 的内容,我们需要将其集成到我们的本地工作副本中。首先,我们使用 git checkout 命令来签出新下载的远程分支。

git checkout coworkers/feature_branch
Note: checking out coworkers/feature_branch'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

此签出操作的输出表明我们处于游离的 HEAD 状态。这是预料之中的,它意味着我们的 HEAD 所指向的引用与我们本地的历史记录不相符。由于 HEAD 指向 coworkers/feature_branch 引用,我们可以从该引用创建新的本地分支。‘游离的 HEAD’ 输出向我们显示了如何使用 git checkout 命令执行此操作:

git checkout -b local_feature_branch

在这里,我们创建了一个名为 local_feature_branch 的新本地分支。这使得更新 HEAD 指向最新的远程内容,我们可以从此处开始继续开发。

使用 git fetch 同步源

以下示例介绍了将本地存储库与中央存储库的主分支同步的典型工作流。

git fetch origin

这将显示已下载的分支:

a1e8fb5..45e66a4 main -> origin/main
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature

来自这些新远程分支的提交在下图中显示为正方形而不是圆形。如您所见,git fetch 使您可以访问另一个存储库的整个分支结构。

原始和主分支

要查看已将哪些提交添加到上游主分支,可以使用 origin/main 作为筛选器来运行 git log

git log --oneline main..origin/main

要批准变更,并使用以下命令将其合并到本地主分支中,请执行以下操作:

git checkout main
git log origin/main

然后,我们可以使用 git merge origin/main

git merge origin/main

原始/主分支和主分支现在指向同一个提交,并且您与上游开发同步。

git fetch 摘要

让我们回顾一下,git fetch 是用于从远程存储库下载内容的主要命令。git fetchgit remotegit branchgit checkoutgit reset 一起使用,来将本地存储库更新为远程存储库的状态。git fetch 命令是协作型 git 工作流的关键部分。git fetch 具有与 git pull 类似的行为,但是 git fetch 更安全且没有任何破坏性。