GIT - Rebase - 如何处理冲突

Sha*_*rop 7 git conflict rebase

我正在开发一个有两个分支的项目:masterfeature

feature分支是在不久前创建的,并且有很多提交.

feature创建分支以来,已经有几个提交master

此时,当我离开rebase时,master我会发生冲突.我解决它们然后rebase --continue.然后我再次得到冲突,并再次解决和rebase --continue.这种情况反复发生,很多时候看起来它们都是出现的相同冲突.

在我看来,这是正在发生的事情:

master(commits)->a->b feature(commits)->c->d->e->f->g

feature分支master->a,然后所有提交都创建.

rebase它重新回到开始feature分支的开始master应用master->b,然后开始应用feature->c此时它有冲突.我决定(接受master更改)并继续.现在它尝试应用feature->d并发现相同的冲突.我必须再次解决这个问题continue.这种情况一再发生.

例如,以下是更改:

master->a
    <div id="foo">

master->b
    <div id="bar">

feature->c
    <div id="fubar">

feature->d
    //Nothing has changed, inherited from feature->c
    <div id="fubar">
Run Code Online (Sandbox Code Playgroud)

我假设,当它到达feature->c它说改foofubar,然后它注意到foo已经改变bar.我决心bar然后它做同样的逻辑应用feature->d

我的两个问题:

1)我对git如何工作/处理提交/冲突/变基的理解是否正确?

2)我怎样才能避免不得不一遍又一遍地解决同样的冲突?我正在考虑压缩功能分支上的所有提交,以便只有一个可以处理.我不确定这是一个好主意还是确切地说是在场景中挤压的最佳方式.

请注意,这是一个非常简化的示例.实际上,我有很多提交,并且在每个众多文件中都存在大量冲突.其中一些在整个rebase --continue过程中看起来是相同的,有些是新的commit.

我的最终目标是尽可能简单地清理这个项目(让功能分支从当前主服务器上重新定位).我不关心提交的历史.

tor*_*rek 10

你的心理形象很接近,但让我们确切地说:

...--o--*--A--B          <-- master
         \
          C--D--...--Z   <-- feature
Run Code Online (Sandbox Code Playgroud)

这就是你现在拥有的:名称master指向提示提交 B(每个单个字母o*代表一个提交).每个提交都返回(left-ish)到之前的提交.两个提交,AB,仅在master.一堆提交仅在此处feature,即C通过Z此处.提交*和所有早期(进一步左)提交都在两个分支上.

什么git rebase是定位提交*通过从提交Z和从尖端向后工作master.然后它知道它需要复制提交CZ.副本将在主人之后立即开始.如果我们使用C'命名副本C,D'副本D等等,最终图形将如下所示:

                C'-D'-...-Z'   <-- feature
               /
...--o--*--A--B                <-- master
         \
          C--D--...--Z         [abandoned]
Run Code Online (Sandbox Code Playgroud)

我认为你已经意识到,通过将每个提交(这是一个完整的快照)转换为一组更改,每个副本一次进行一次提交.要得到什么改变C,Git的作用:

git diff <hash-of-*> <hash-of-C>
Run Code Online (Sandbox Code Playgroud)

混帐然后尝试应用这一变化的快照B,但它并不容易申请,所以混帐试图做一个合并:它比较*B,并认为它应该改变<div id="foo"><div id="bar">,根据是什么; 但<div id="foo"> <div id="fubar">根据*-vs- ,它应该改变C.这是第一次合并冲突.

所以,你解决这个并提交(好吧,git rebase --continue提交):

                C'       <-- HEAD (rebase in progress)
               /
...--o--*--A--B          <-- master
         \
          C--D--...--Z   <-- feature
Run Code Online (Sandbox Code Playgroud)

和Git继续复制D,通过版本比较DVS C获得补丁.

这时候,应该没有<div id="foo"><div id="fubar">改变,所以你不应该在这里得到一个合并冲突.为了确定,请尝试git show-ing commit D,它同样将它与之比较C,产生差异.

但是,您可能会被白色空间变化或类似情况所困扰.值得仔细研究每个git diff输出,并检查诸如行尾属性之类的内容(如果您正在使用它们)(CRLF转换).行尾结束通常会影响每个文件中的每一行,但您可以获得单行问题,例如,取决于谁使用了什么编辑器.

我怀疑一个更可能的问题:git diff错误的行上进行同步.它找到一些匹配的微不足道的东西,比如读取的行},并使用它们来决定两个文件重新同步,然后挑出"错误的变化".如果是这种情况,那么治愈 - 如果有的话 - 是指示Git使用更聪明的差异.特别地,patience差异不是在平凡线上同步,而是仅在重要(即,非重复)线上同步.这可能会或可能不会实际帮助 - 在您的提交上运行git diff --diff-algorithm=patience(或git show使用相同的参数)可能会告诉您.是否可以使用不同的diff算法获取rebase取决于你的Git版本.

除了为什么Git的似乎是重复的变化,当它应该只有谜其他的变化C航班吗D,有一两件事你可以做,以帮助是利用git rerere获得的Git来重新 -使用一个重新重新溶液(由此得名).基本上,当Git遇到合并冲突时,如果rerere启用,Git会将冲突的部分写入其数据库,然后当您git add解析文件时,Git会写入解决方案(与原始冲突配对).然后,下次Git遇到合并冲突时,它会检查保存的rerere数据:如果冲突是针对同一个补丁,则会拉出记录的分辨率,并在不与您交互的情况下使用该分辨率.

您确实可以通过feature在提交时重新设置*(使用交互式rebase)来将一些或所有功能提交压缩在一起.由于这些补丁不会与自身冲突 - 至少只要它们按顺序回放 - 这可以让你减少需要解析的提交数量.你是否应该这样做取决于你:一般来说,如果你正在变基础,你无论如何都会获得新的替换提交,所以你不妨为将来的调试或其他代码探索做出"尽可能漂亮"的新提交.显然,最好有五个"做一些有趣的事情,但几乎是独立的"提交,而不是50"做一件事的片段,做另一个片段,修复前一个片段,做另一个片段,确定那件事做完了接下来的事情,哎呀修复微小的错误,......"所以这些人非常适合挤压在一起.但是,通常最好有五个"做一件事"提交,而不是"做五件事"提交:这意味着如果五个中的一个中有一个错误,你就可以修复而不用担心其他四个.


dah*_*byk 7

我不关心提交的历史。

如果您真的不关心历史,agit merge --squash将让您立即解决所有冲突并生成包含所有更改的单个提交。

要基本上--squash就地执行此操作,您可以执行以下操作:

git branch -m feature feature-old
git checkout master -b feature
git merge --squash feature-old
Run Code Online (Sandbox Code Playgroud)

你解决所有冲突(一次)后,您将创建一个单一的承诺上featuremaster作为父母。

话虽如此,我是保留历史的粉丝。一定rerere要先试试。您也可以尝试就地rebase --interactive(例如git rebase -i $(git merge-base HEAD master))压缩修复类型的提交,而不完全消除所有离散提交。