Git Rebase冲突:谁是HEAD?

时间:2014-04-21 23:33:17

标签: git meld

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

git checkout experimentalbranch
git fetch remoterepo
git rebase remoterepo/developmentbranch

此时,我遇到了冲突。但是,我不熟悉任何这些更改(我会重新定义几周的更改,因为他们没有立即合并我的更改)。此外,这是我第一次做rebase。我更习惯merge

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

2 个答案:

答案 0 :(得分:74)

TL; DR(2018年5月添加)

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

请注意,我们在此处关注的案例会在您运行时发生:

git checkout somebranch; git rebase origin/their-branch

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

一开始,HEAD提交就是他们的分支,因此,如果您使用git checkout --oursgit checkout --theirs,则--ours表示< em>他们的 - origin/their-branch的最终提交 - 而--theirs表示你的,第一次提交是你的。这是Git每天正常的混淆(见What is the precise meaning of "ours" and "theirs" in git?),而不是导致原始问题的原因。

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

同样,HEADlocal--ours 是一个通过组合您的更改及其更改而构建的提交,以及另一个提交({ {1}}或remote>>>>>>>)是您自己的提交,rebase正在尝试复制--theirs上方。

合并时(包括重新定位,这是内部重复“合并”的特殊情况),涉及两个“头”(两个特定的分支提示)。我们称这些为HEADyour-branch

origin/their-branch

这一点通常(并且不足为奇)令人困惑,尽管如此标记就足够了。

更糟糕的是,git使用 G - H -------- <-- HEAD=your-branch / \ ... - E - F M <-- desired merge commit [requires manual merge] \ / I - J - K - L <-- origin/their-branch --ours来引用合并期间的两个头部提交,其中“our”是您所在的(commit --theirs当你运行H时,他们的“他们”就是他们的(提交git merge)。但是当你正在做一个反叛时,两个头是相反的,所以“我们的”是你正在改变的头,即他们更新的代码 - 而“他们的”是你目前正在改变的提交,即你自己的代码。

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

L

git需要做的是复制提交 G - H <-- HEAD=your-branch / ... - E - F \ I - J - K - L <-- origin/their-branch G的效果,即H提交git cherry-pick,然后使用提交G再次执行此操作。但要做到这一点,git必须首先切换提交H,在内部(使用“分离的HEAD”模式):

L

现在它可以通过比较提交 G - H <-- your-branch / ... - E - F \ I - J - K - L <-- HEAD, origin/their-branch F的树(以查看您更改的内容),然后比较GF(到看看您的某些作品是否已在L中)并进行L中尚未进行的任何更改并添加。这是内部的“合并”操作。

L

如果合并不顺利, G - H <-- your-branch / ... - E - F G' <-- HEAD \ / I - J - K - L <-- origin/their-branch 仍然留在提交HEAD(因为提交L尚不存在)。因此,是的,G'是他们发展部门的负责人 - 至少现在是这样。

一旦HEAD的副本存在,G移至HEAD,git会尝试以同样的方式复制G'的更改(diff {{ 1}} vs H,然后差异G vs H,并合并结果):

F

同样,如果合并失败并需要帮助,那么G'指向 G - H <-- your-branch / ... - E - F G' - H' <-- HEAD \ / I - J - K - L <-- origin/their-branch 而不是HEAD,因为G'尚不存在。

一旦合并全部成功并且提交H'并且H' 执行,git将从提交G'中删除标签H',并生成它指向提交your-branch

H

现在你已经重新定位了,H'再次成为你的期望。但是在rebase期间, G - H / ... - E - F G' - H' <-- HEAD=your-branch \ / I - J - K - L <-- origin/their-branch 要么是他们的分支提示(commit HEAD),要么是通过其分支提示复制和追加的新提交之一; HEAD表示在L结束时生成的分支,而--ours表示正在复制的提交(上面的L--theirs)。

(这基本上是暴露了如何它做它做什么的原始机制的git,这在git中发生了相当多。)

答案 1 :(得分:3)

解释

在本节中,我们将看到我们被问及的缺陷:

  

谁是HEAD?

HEAD 您的回购协议的当前提交。大多数时候HEAD指向您分支中的最新提交,但事实并非如此。 HEAD真的只是意味着&#34;我的回购目前指向的是什么&#34;。

如果提交的HEAD引用不是任何分支的提示,则称为&#34; detached head &#34;。< / p>

  

它是开发分支的HEAD吗?

在进行合并或重组的那一刻,HEAD 会立即转到指向已创建或重构的提交,因此将指向开发分支< / em>的

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

实践

在本节中,我们将看到_how_处理用户执行的一些操作

当用户进入:

# 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
  

此时,我遇到了冲突。但是,我对这些变化并不熟悉(我会因为他们没有立即合并我的更改而改变数周的变更)。而且,这是我第一次做反叛。我更习惯于合并。

分支的结合有两种方式:

  • git merge

  • git rebase。

注意

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

* 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

git merge

最着名的形式是git merge,它在每个分支的最后两个快照和两者的共同祖先之间执行三个波段的融合,创建一个混合更改的新提交。

例如:

git checkout remoterepo
git merge experimentalbranch

它会产生我们:

*   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

git rebase

git 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
  

什么是起源?

origin git为您的主远程仓库提供的默认名称。你的盒子有自己的仓库,你最有可能推出一些你和你的同事所推动的远程仓库。那个远程回购几乎总是被称为原产地,但它不一定是。