git pull
的合并/重组步骤将远程跟踪分支合并/重新绑定到当前分支上。
我想知道git pull
然后将当前分支检出到工作目录中吗?或者我应该自己看看?
我的问题是我认为合并步骤修改了git存储库中的当前分支,而工作目录尚未与当前分支保持同步,因此需要检查修改后的当前分支进入工作目录。
但我不确定git pull
的合并步骤是否已经完成,或者我是否应该在git pull
之后自行完成。
答案 0 :(得分:2)
当前分支 在工作目录中签出。
在合并/ rebase之后,分支已向前移动到另一个提交。
所以是的,git将检查该提交,以便你留在当前分支。
答案 1 :(得分:2)
简短的回答是" no",这实际上是一个完整且技术上正确的答案,但有点不满意并且很可能误导:在所有好中例如,最终状态是好像 git已经完成了结账。如果你愿意的话,你可以停在这里。 : - )
长期答案有点长,在现代版本的git中变得复杂,因为您可以将git rebase
设置为" autostash"。但我们再次回到git pull
运行git fetch
后跟git merge
或git rebase
的事实。
fetch
步骤更简单,因为它不需要知道或关心工作目录。它会联系指定的 remote
(如果您没有指定一个,则从当前分支branch.$branch.remote
获取),为该远程提供一些refspec(s) (来自您传递的其他参数,或者您未通过任何配置的配置),并根据需要从远程调用提交和其他对象。这些提交和其他对象被推送到您的存储库中的存储中,在那里它们可以安全地排除在外,但随时可用。一些"远程跟踪"可以更新分支名称,并且在任何情况下,将带来的分支头部放入特殊FETCH_HEAD
文件中(特别是,FETCH_HEAD
获取与之一起的SHA-1 ID每个分支机构名称)。
要查看整个名称/ SHA-1 ID映射内容,请运行git ls-remote remote
(例如git ls-remote origin
)。这将联系远程并从中获取git fetch
获取的相同信息,然后在命令窗口中将其打印出来。它对其他任何东西都没有任何改变,所以它只是使用了一点网络带宽,而且在我看来它很有教育意义。 (如果遥控器上有很多分支和标签,您可能需要来回滚动以查看所有输出,或将输出保存在文件或其他任何内容中。)
merge
或rebase
步骤是棘手的位置。让我们退出嵌套并考虑两者。我们也只考虑与单个目标合并的情况(即正常的日常合并,而不是git的花式章鱼合并)。
如果你从干净的工作树开始(和索引),那么描述现在发生的事情要容易得多。让我们假设一个干净的工作树开始。
fetch
步骤带来了一些提交。 merge
或rebase
找到合适的合并基或rebase目标,然后按照指示执行合并或rebase:
对于合并,git会找到合并基础。通常,这是一个特定的提交。 (在某些情况下,有多个合并基础候选者,git也处理这些,但是不要担心它们。)您可以将此视为您的分支和其他分支分歧的点:
<--older--time increases as we move right--newer-->
[see footnote 1]
o - o <-- your branch (master)
/
... - o - *
\
o - o - o <-- their branch (origin/master)
在此图中,每个小o
节点表示提交。合并基础是标记为*
而非o
的提交。您的分支master
的提示最多提交位于顶行的最右侧o
,其分支origin/master
的提示最多提交是最右侧{{1}在底线。
让我们调用你的分支o
的最尖端提交,只是为了具体。 (它有自己独特的SHA-1 ID以及它的真实姓名&#34;,但我们只需称它为A
。)让我们来电话合并基础A
和其分支B
的提示,并重绘该图表:
C
要执行合并(当需要合并时),git首先在commit o - A <-- your branch (master)
/
... - o - B
\
o - o - C <-- their branch (origin/master)
和commit B
之间运行diff,就好像你A
一样(填写实际内容)当然,git diff B A
和B
的SHA-1;它使用其差异代码的内部版本,而不是简单地读取文字A
文本输出。这个差异告诉git&#34;你改变了什么&#34;自公共基础git diff
。
接下来,git运行B
(当然再次使用内部格式)。这个差异告诉git&#34;他们改变了什么&#34;因为同样的共同基础。
最后,git尝试组合两个差异。如果你添加了一个文件并且他们没有,那么git会保留你添加的文件。如果您将文件git diff B C
中neighbor
的拼写更改为neighbour
并且他们没有,则会保留您的更改。如果他们删除了您没有触摸的文件,或者从您没有触及的文件中删除了一行,git会保留其更改。如果您将完全相同的更改为README
,则git会保留该更改的一个副本(而不是两个副本)。 Git适用于所有&#34;保持&#34;更改基本版本并将结果写入工作树,现在完成合并时没有合并冲突。 git认为,结果已经准备好了。 (请注意,即使您所做的某些更改要求系统保留已删除的文件,git现已删除,也是如此。也就是说,假设他们表示&#34;哦,看看,此文件未被使用,请将其删除&#34; 你表示&#34;哦,哎呀,我忘了使用该文件,让我们使用它&#34; .Git并不知道这些变化实际上是冲突的:它可以告诉我们,差异中的线条不会发生碰撞。)
下一步取决于你是否给了weather.h
标志。 2 无论如何都会抑制提交。如果你没有禁止提交,--no-commit
提交这个没有明显冲突的变更集,作为&#34;合并提交&#34;有两个父母:
git merge
此时,工作树与新提交 o - A ----- M <-- your branch (master)
/ /
... - o - B /
\ /
o - o - C <-- their branch (origin/master)
匹配。虽然没有检查 out ,但已将 (已提交)中的检查为合并。
如果您 说M
,或者存在合并冲突,则合并将停止并让您修复和/或提交合并。更改只是存在于您的工作目录中。如果您决定提交结果,那将是合并提交。 Git知道这一点,因为它会在合并过程中留下跟踪文件&#34;&#34;。如果您决定取消与--no-commit
的合并,则会删除跟踪文件。
对于rebase,git经历了类似的过程。但是,它不是找到合并库,而是找到上游没有的提交集。我们可以再次绘制该图,但是让我们使用不同的节点名称:
git merge --abort
在这种情况下,git会发现你的两次提交( A - B <-- your branch (master)
/
... - o - o
\
C - D - E <-- their branch (origin/master)
和A
)和复制它们(使用B
或多或少)。这种机制可能很复杂,所以我们在此注意每个git cherry-pick
操作都需要更新工作树并进行新的提交。如果一切顺利,我们会将cherry-pick
,A
的副本以及A'
B
的副本加载; git将分支名称移动到B'
;最终的图纸看起来像这样:
B'
因为每个cherry-pick步骤都会更新您的工作树并从中提交,所以您的工作树与最终提交 A - B [abandoned]
/
... - o - o A' - B' <-- your branch
\ /
C - D - E <-- their branch
匹配,而不是因为它已经检查 out ,但是因为它已在(已提交)中检查,与合并案例完全相同。
如果你从一个肮脏的工作树开始(或&#34;脏索引&#34;,即任何未签入的更改),那么描述起来就有点难了,但不是太多。我们仍然有两个案例:
对于合并,git仍会尝试合并您的更改及其更改,但它会尝试执行此操作,同时保留其他未提交的更改。如果成功,它会像往常一样从结果中提交,除非像往常一样被禁止。如果它失败了,它会像往常一样停止并让你清理混乱。
关于这一点的好处是,即使从干净的工作树合并失败,您有时也可以生成有效的合并。关于这一点的坏处在于,当你不是故意的时候,它很容易做到这一点,并且随着你的变化和他们的变化一起变得非常难以退出。它通常只是一个坏主意:提交或藏匿,然后从一个干净的状态合并,如果你愿意,可以与B'
合并。然后,您可以在执行任何修复后运行测试并执行自己的提交。 (请注意,您还可以在合并提交时使用--no-commit
。)
对于rebase,如果工作树不干净,通常git commit --amend
将拒绝运行。这使得这很容易。但是,由于git 1.8.4,git rebase
现在具有可配置的rebase
设置。如果你设置了这个,那么你的rebase.autostash
将在这种情况下为你运行rebase
,然后进行rebase,然后(如果一切顺利)为你弹出藏匿。这种模式有一个烦人的(但不是致命的)错误,直到git 2.0.1才得到修复,我建议一般反对它 - 我认为最好只做一个检查点提交,然后清理它后来的清理通行证(在#34之前通过清理通常会很好;最终确定&#34;提交,这是时候挤掉临时检查站;在那之前,他们自然地进行自然改造,没有任何骚扰自动驾驶的危险)。
1 虽然图表说&#34;时间增加到右边&#34;但从技术上讲,右边的节点实际上只是左边节点的后继节点。当您从远程提取提交时尤其如此。这些提交中的时间戳是在其他计算机上完成的,即使你很擅长保持自己的计算机与某个原子钟同步,谁知道他们的时钟是/是/是正确的?那些时间戳可能完全被打破。时间顺序无法保证,只是&#34;可能&#34;。
2 除了git stash
之外,--no-commit
还带有git merge
标志,这有两个副作用:(1)最终提交不是合并提交完全和(2)在完成合并的所有常规工作之后,--squash
在没有提交的情况下停止(就像git merge
一样)。也就是说,--no-commit
内部做的是阻止最终提交和停止--squash
编写特殊状态文件,告诉git它在中间合并。这样,您之后必须执行的手动提交是普通的非合并提交。