Git Rebase冲突:谁是HEAD?

Jos*_*eph 52 git meld

我有这个项目,远程仓库有主要的开发分支,我有一个包含实验分支的分支.rebase在推到我的前叉之前,我需要从开发分支更改为我的实验分支.它就像:

git checkout experimentalbranch
git fetch remoterepo
git rebase remoterepo/developmentbranch
Run Code Online (Sandbox Code Playgroud)

到这个时候,我遇到了冲突.但是,我不熟悉任何这些变化(我正在改变几周的变化,因为他们没有立即合并我的更改).而且,这是我第一次这样做rebase.我比较习惯merge.

在meld中,它通常就像<<LOCAL||REMOTE>>merge,听起来非常直观.但在rebase,它是<<HEAD||COMMIT MESSAGE>>.是谁HEAD?它是HEAD开发分支吗?它是开发分支或其他地方的最新代码吗?

tor*_*rek 83

TL; DR(2018年5月新增)

从根本上说,整个事情至少有点令人困惑,因为Git让它的内部工作能够直接显示给你.

请注意,我们在这里关注的情况发生在您运行时:

git checkout somebranch; git rebase origin/their-branch
Run Code Online (Sandbox Code Playgroud)

或类似的.rebase暂时停止以强制您解决合并冲突,之后您应该git add解决冲突并运行git rebase --continue.(如果你使用一些合并工具git mergetool或一个花哨的GUI界面,那个界面可能会以某种其他方式为你做一些或所有这些,但在下面,它是git add解析后的文件并运行git rebase --continue.)

在一开始,HEAD承诺为他们的分支,所以,如果你使用git checkout --oursgit checkout --theirs,--ours意味着他们 -the最终提交的origin/their-branch-while --theirs意味着你的,第一次提交你基础重建.这是Git每天正常的混乱(请参阅git 中"我们的"和"他们的"的确切含义是什么)并不是导致原始问题的原因.

然而,后来,HEAD提交实际上是一种混合.这是在最新提交时复制一些提交的结果.您现在正在使用自己部分构建的系列提交与您自己的原始提交之间发生冲突.这种冲突的根源通常是"他们"所做的事情(在此过程中发生了变化origin/their-branch).您仍然需要解决此冲突.当你这样做时,你可能会看到在以后的提交中再次出现相同的冲突.

此外,HEADlocal或者--ours提交的是重订已结合你的变化及其变化建成,其他承诺(remote>>>>>>>--theirs)是你自己的承诺,重订,这是试图复制之上HEAD.

更长

合并时(包括重新定位,这是内部重复"合并"的特殊情况),涉及两个"头"(两个特定的分支提示).让我们把这些your-branchorigin/their-branch:

              G - H --------      <-- HEAD=your-branch
            /               \
... - E - F                   M   <-- desired merge commit [requires manual merge]
            \               /
              I - J - K - L       <-- origin/their-branch
Run Code Online (Sandbox Code Playgroud)

这一点通常(并且不足为奇)令人困惑,尽管如此标记这一点已经足够清楚了.

但是,更糟糕的是,git 在合并期间使用--ours--theirs引用两个头部提交,H当你运行时git merge,"我们的"是你所处的(提交),而"他们的"就是他们的(提交L).但是当你正在做一个反叛时,两个头是相反的,所以"我们的"是你正在改变的头,即他们更新的代码 - 而"他们的"是你目前正在改变的提交,即你自己的代码.

这是因为rebase实际上使用了一系列的挑选操作.你从很多相同的图片开始:

              G - H           <-- HEAD=your-branch
            /
... - E - F
            \
              I - J - K - L   <-- origin/their-branch
Run Code Online (Sandbox Code Playgroud)

什么混帐需要做的,是要复制提交的效果GH,即git cherry-pick提交G,然后提交再做一遍H.但要做到这一点,git必须首先在内部切换到提交L(使用"分离的HEAD"模式):

              G - H           <-- your-branch
            /
... - E - F
            \
              I - J - K - L   <-- HEAD, origin/their-branch
Run Code Online (Sandbox Code Playgroud)

现在它可以通过比较提交树FG(看你改变了什么),然后比较Fvs L(看看你的某些作品是否已经存在L)并进行任何尚未进行的更改L并添加它来启动rebase操作.这是内部的"合并"操作.

              G - H           <-- your-branch
            /
... - E - F                   G'   <-- HEAD
            \               /
              I - J - K - L   <-- origin/their-branch
Run Code Online (Sandbox Code Playgroud)

如果合并不顺利,HEAD仍然处于提交状态L(因为提交G'尚不存在).因此,是的,HEAD是他们发展部门的负责人 - 至少现在是这样.

G但是,一旦存在副本HEAD移动到G'并且git尝试以H相同的方式复制更改(diff Gvs H,则diff Fvs G',并合并结果):

              G - H           <-- your-branch
            /
... - E - F                   G' - H'   <-- HEAD
            \               /
              I - J - K - L   <-- origin/their-branch
Run Code Online (Sandbox Code Playgroud)

同样,如果合并失败,并且需要帮助,你留下了HEAD指向G',而不是H'因为H'尚不存在.

一旦合并成功并提交G'H' 确实存在,git your-branch将从提交中删除标签H,并使其指向提交H':

              G - H
            /
... - E - F                   G' - H'   <-- HEAD=your-branch
            \               /
              I - J - K - L   <-- origin/their-branch
Run Code Online (Sandbox Code Playgroud)

而你现在已经重新定位,并HEAD再次成为你所期待的.但是在rebase期间,HEAD要么是他们的分支提示(提交L),要么是其中一个新提交被复制并追加到他们的分支提示之外; 并且--ours意味着在Lwhile 结束时生成的分支--theirs意味着从(GH上面)复制提交.

(这基本上是暴露了它如何做它的原始机制的git ,这在git中发生了很多.)

  • 阅读本文时,当我在冲突文件中遇到 `&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD` 时,我仍然不确定该位是我的还是他们的?答案的复杂性是否意味着可以将其解释为“视情况而定”? (3认同)
  • 所以基本上`HEAD`,在第一个操作中是“他们的分支”的`HEAD`,在随后的操作中,`HEAD`现在是我新追加的提交? (2认同)
  • 是的; 但这可能会很令人困惑,因为它们是在您正在“增长”的分支上新添加的提交,而该分支还没有名称。在上图中,它们位于中间行,而不是顶部或底部行。 (2认同)
  • @dumbledad:是的,这取决于你是否正在执行“git merge”或“git rebase”(或者,就此而言,“gitcherry-pick”或“git revert”)。在所有情况下,“HEAD”都是实际命令运行时的“HEAD”,因此最令人困惑的是“git rebase”运行“gitcherry-pick”(用于交互式 rebase)或“git am”(用于非交互式)来自一个独立的 HEAD,该 HEAD 正在目标上增加新的提交。 (2认同)

Nic*_*ela 9

定义

在本节中,我们将看到我们被要求回答的缺陷:

头是谁?

HEAD您的存储库当前的提交。大多数时候 HEAD 指向分支中的最新提交,但情况不一定如此。 HEAD实际上只是意味着“我的仓库当前指向什么”。

如果提交HEAD引用的不是任何分支的顶端,则称为“ detached head”。

是开发部门的负责人吗?

在进行合并或变基时,HEAD 立即传递指向创建或重构的提交因此将指向开发分支

git bash我们可以看到的HEAD情况下,列出提交:

# Normal commit list
git log
# List of commit in a single line
git log --oneline 
# All commits graphically-linear (Recommended as alias)
git log --all --graph --decorate --oneline
Run Code Online (Sandbox Code Playgroud)

实践

在本节中,我们将了解用户执行的一些操作的工作原理

当用户继续:

# Command to change from the branch to the current one to experimentalbranch
git checkout experimentalbranch
# Command that traverses the typical workflow to synchronize its local repository with the main branch of the central repository (remoterepo)
git fetch remoterepo
# git fetch origin
# git fetch origin branch:branch
# With the command git rebase, you can take all the changes confirmed in one branch (remoterepo), and reapply them over another developmentbranch
git rebase remoterepo/developmentbranch
Run Code Online (Sandbox Code Playgroud)

这时候我就遇到了矛盾。但是,我不熟悉这些更改中的任何一个(我正在重新调整数周的更改,因为它们没有立即合并我的更改)。另外,这是我第一次做rebase。我更习惯于合并。

分支的联合有两种方式完成:

  • git合并

  • git 变基。

笔记

对于示例,我们将使用以下树

* a122f6d (HEAD -> remoterepo) Commit END
* 9667bfb Commit MASTER
| * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3
| * 110b2fb Commit 2
| * e597c60 Commit 1
|/
* 0e834f4 (origin/remoterepo) First commit
Run Code Online (Sandbox Code Playgroud)

git合并

最著名的形式是git merge,它对每个分支的最后两个快照和两个分支的共同祖先之间的三个带进行融合,创建具有混合更改的新提交。

例如 :

git checkout remoterepo
git merge experimentalbranch
Run Code Online (Sandbox Code Playgroud)

它会产生我们:

*   003e576 (HEAD -> remoterepo) Merge branch 'experimentalbranch' in remoterepo
|\
| * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3
| * 110b2fb Commit 2
| * e597c60 Commit 1
* | a122f6d Commit END
* | 9667bfb Commit MASTER
|/
* 0e834f4 (origin/remoterepo) First commit
Run Code Online (Sandbox Code Playgroud)

git 变基

git rebase基本上它的作用就是一一收集一个分支中确认的更改,然后将它们重新应用到另一个分支上

每当将 rebase应用于本地且尚未上传到任何远程存储库的提交时,使用 rebase 可以帮助我们避免冲突。如果您对后者不小心并且合作伙伴使用了受影响的更改,那么您肯定会遇到问题,因为这些类型的冲突通常很难修复

例如 :

git checkout remoterepo
git rebase experimentalbranch


* f8a74be (HEAD -> remoterepo) Commit END
* 4293e9d Commit MASTER
* b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3
* 110b2fb Commit 2
* e597c60 Commit 1
* 0e834f4 (origin/remoterepo) First commit
Run Code Online (Sandbox Code Playgroud)

什么是起源?

origingit 为您的主远程存储库提供的默认名称。您的盒子有自己的存储库,您很可能会推送到您和所有同事推送到的某个远程存储库。该远程存储库几乎总是称为 origin,但不一定如此。