Sha*_*rop 7 git conflict rebase
我正在开发一个有两个分支的项目:master和feature
该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它说改foo到fubar,然后它注意到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)到之前的提交.两个提交,A和B,仅在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"做一件事的片段,做另一个片段,修复前一个片段,做另一个片段,确定那件事做完了接下来的事情,哎呀修复微小的错误,......"所以这些人非常适合挤压在一起.但是,通常最好有五个"做一件事"提交,而不是"做五件事"提交:这意味着如果五个中的一个中有一个错误,你就可以修复它而不用担心其他四个.
我不关心提交的历史。
如果您真的不关心历史,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)
你解决所有冲突(一次)后,您将创建一个单一的承诺上feature有master作为父母。
话虽如此,我是保留历史的粉丝。一定rerere要先试试。您也可以尝试就地rebase --interactive(例如git rebase -i $(git merge-base HEAD master))压缩修复类型的提交,而不完全消除所有离散提交。