master
、branch1
和branch2
。如果我当前在master
分支上,那么执行git pull
命令会获取并合并这三个分支的变化吗?我想我也可以自己进行实验...master
、branch1
和branch2
。如果我当前在master
分支上,那么执行git pull
命令会获取并合并这三个分支的变化吗?我想我也可以自己进行实验...简短的回答是“不”—或者甚至是“不和是”,如果只读您问题的标题—但这有些误导。
pull命令允许选项,其中许多具有有趣(混乱和潜在的非常不友好)的影响。
记住,侧边栏:确保您正确理解Git文档所称的远程分支、远程跟踪分支和跟踪分支之间的差异,以充分利用以下说明。请注意,这些是Git(和git-scm.com)使用的术语。长时间以后,我最初写下这个答案,我发现这些术语只会让人们困惑——包括我自己!——而且现在,我更喜欢我的术语。我喜欢说作为另一个(远程)Git存储库上看到的分支名称,而不是远程分支;我称之为远程跟踪名称,而不是远程跟踪分支名称(例如
origin/master
);而我使用设置上游的分支名称这个短语来代替跟踪分支。但是要准备好Git文档使用他们的术语。
git pull
基本上是git fetch
和git merge
的简写。 1 pull
命令将大多数参数直接传递到fetch
步骤。 例如,如果您执行git fetch origin br
,则fetch
步骤将获取远程(origin
)的名称和br
作为“refspec”。 在Git版本1.8.4之前,这会防止git fetch
更新任何远程跟踪分支,但自1.8.4以来,显式获取分支br
也会更新您的origin/br
(假设涉及的远程名为origin
)。git fetch
将会获取远程默认的refspecs集合,通常是“所有分支”。这意味着,无论是git fetch
(假设是origin
)还是git fetch origin
,都会更新所有与origin
相关的远程跟踪分支,前提是你正在运行一个相当现代的(1.8.4或更高版本)Git。(在足够旧的Git版本中,我认为pull
命令在fetch步骤期间会变得更加严格。)origin/*
远程跟踪分支之后,pull
代码转移到git merge
步骤。对于这部分,Git非常关心你现在所在的分支以及它将要与哪个“远程分支”合并。如果像你的示例一样,你当前在master
上,并且它将要与origin
的master
合并,Git将使用任何新的内容来运行git merge
步骤,这些内容位于origin/master
下面(请注意此处的斜杠)。
我在上面多次使用了“refspec”一词,但从未定义过。
“refspec”在其第二个最简单的形式下,只是一对分支名称,例如master:master
,develop:develop
等。
这对通常(但不总是)在它们之间的冒号:
两侧具有相同的两个分支名称。 其中一个是您的名称-您的分支,在您的存储库中-另一个是他们的名称,也就是他们在他们的存储库中用于他们的分支的名称。
git push origin master:master
。这意味着“打包我在我的主分支中的内容,通过互联网电话呼叫名为origin
的远程主机,将包发送给他,并询问他是否将其作为他的master
分支。”您还可以在左侧使用提交ID或单词HEAD
:git push origin HEAD:master
表示“获取当前所在的提交,要求远程origin
将其作为他的master
分支”。git fetch
时,双方会交换位置,通常你还需要在你想要的名称前面添加origin/
(或你的远程名称)。也就是说,你会得到他的master
,但在你的仓库中将其称为origin/master
。因此,你需要执行git fetch origin master:origin/master
等操作。4 如果你执行git fetch origin master:master
,你可能会覆盖自己在主分支上的工作。5
有一个与fetch
和pull
相关的奇怪事情。我说这是refspec的“第二简单”形式,最简单的形式只是像master
这样的名称。这取决于你正在做什么:fetch
表示“带上他的master
,但不一定在我的本地存储库中为其指定任何名称,只需保存哈希ID。”对于push
,它表示“给他我的master
,并要求他将其称为master
”。git fetch
带来他们的主分支(以及其他分支),而没有为其提供本地名称,则它将仅在Git的FETCH_HEAD
文件中保存ID(以及它们对分支的名称)。在较新(1.8.4及更高版本)的Git版本中,git使用fetch =
配置项来确定要更新哪些远程跟踪分支。
git pull origin master branch
(不要这样做)如果你让git fetch
带来多个分支,那么这很好用(至少在Git 1.8.4或更高版本中是这样)。但是,如果你告诉git pull
获取多个分支,它会表现得很糟糕。
fetch
步骤很好用。问题出在merge
步骤。
pull
命令要求git merge
将多个分支合并到当前分支中。Git称之为“章鱼合并”。除非你了解高级分支操作,否则你几乎肯定不想这样做。所以不要这样做。
我建议先执行一个git fetch
,默认情况下会带来所有分支,然后再执行单个的git merge
或git rebase
操作。这样你就可以看到自己在做什么了。
1如果配置或指定,则可以使用git rebase
。与合并相比,变基通常更好,但这取决于具体情况。我的建议是首先使用git fetch
,然后将自己的git rebase
或git merge
作为单独的步骤执行,至少在您还不熟悉Git时要这样做。我认为这样做实际上会更少让人困惑,尽管不可否认的是,您需要输入两个命令而不是一个。
2从技术上讲,它是该远程配置中fetch =
行中的内容。对于远程origin
,正常行为为fetch = +refs/heads/*:refs/remotes/origin/*
,这就是Git知道如何将origin的分支重命名为您的origin/whatever
分支的方式。
3技术上,Git只使用一个原始哈希ID,在名为FETCH_HEAD
的文件中保存。这里带引号的“远程分支”是标准的Git术语:在通过git fetch
命令将提交提供给您的Git的存储库上看到的分支名称。
4我忽略了另一件事,即前面的加号符号:fetch =
行通常用于获取“他们的主分支”,您通常要忘记关于“他们的主分支”的任何先前想法,因此该行具有前导加号符号。这启用了“force”标志,即使不是快进操作也会进行更新。 fetch =
行还完全拼写了所有内容,以避免如果意外命名本地分支origin/something
而出现问题,并使用*
字符来匹配多个分支名称。
5如果您确实覆盖了自己的工作,几乎总能找回它。 Git确实尝试至少保留所有内容30天。我们将把“如何取回它”留给其他SO条目。
git pull
不再是一个脚本,Git 2.29开始支持使用SHA-256而不是SHA-1。) - torekgit fetch
是更新或者没有更新远程跟踪分支名称的命令。git pull
命令会运行 git fetch
,所以 git pull
有两个步骤:(1) 运行 git fetch
,然后 (2) 再运行另一条 Git 命令(由你选择)。我们关心的是 git pull
中的 git fetch
步骤。如果你输入 git pull origin br
,你运行的是 git fetch origin br
。也许有更清晰的表述方法。 - torekgit pull
没有参数,会执行git fetch <origin>
步骤,更新所有远程跟踪分支,然后执行git merge FETCH_HEAD
吗? - S.Bgit merge
(或 git rebase
)命令并不直接使用 FETCH_HEAD
,而是从中提取提交哈希值,并在最新的 Git 版本(由于它现在是一个大型 C 程序)中写入了 fetch 步骤的哈希值到 FETCH_HEAD
中(因为相同程序已经知道了它们,所以无需再次检索)。 - torekgit pull --all
拉取所有已跟踪的远程分支,或者使用git fetch --all
获取它们并稍后再决定如何处理。请注意,pull通常会自动合并任何更改,这很少是你想要的。不,只将合并更改拉到当前本地分支。
根据这个答案 https://dev59.com/gG855IYBdhLWcg3weUQQ#59793998,我已经添加了一个函数到/etc/bash.bashrc
来实现这个功能:
git_pull() {
echo - pulling all tracked local branches from "origin" remote
orig_branch=$(git branch | grep "*" | sed "s/[ *]*//") # getting name of current branch via asterisk
git fetch | return 1
for branch in $(git branch | sed "s/[ *]*//") ; do # remove spaces and asterisk
git checkout $branch && git merge --ff-only FETCH_HEAD
done
echo - checking out to branch where function was called from
git checkout $orig_branch
}; export -f git_pull