【问题标题】:GIT - Rebase - How to deal with conflictsGIT - Rebase - 如何处理冲突
【发布时间】:2017-07-14 10:43:31
【问题描述】:

我正在从事一个有两个分支的项目:masterfeature

feature 分支是不久前创建的,并且有许多提交。

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

此时,当我从master 转到rebase 时,我遇到了冲突。我解决了它们,然后rebase --continue。然后我再次遇到冲突,再次解决和rebase --continue。这种情况一遍又一遍地发生,而且很多时候似乎它们是正在出现的相同冲突。

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

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

feature 是从 master->a 分支出来的,然后创建了所有提交。

当我rebase 时,它会倒回到从master 分支的feature 的开头应用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">

我假设当它到达feature-&gt;c 时,它说将foo 更改为fubar,然后它注意到foo 已经更改为bar。我解析为bar,然后它执行相同的逻辑应用feature-&gt;d

我的两个问题:

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

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

注意,这是一个非常简化的示例。实际上,我有更多的提交,并且在每个具有许多冲突的众多文件中。其中一些在整个rebase --continue 过程中似乎是相同的,而一些对于每个commit 来说都是新的。

我的最终目标是尽可能简单地清理这个项目(让功能分支重新基于当前主节点)。我不关心提交的历史。

【问题讨论】:

    标签: git conflict rebase


    【解决方案1】:

    当你这样做时

    git pull --rebase origin/upstream master
    

    它检查是否有其他人最近的代码合并。如果是这样,您必须使您当前的工作树与上游的内容对齐。

    您可以看到更改后的文件,您需要重新查看

    git status
    

    解决后,

    git add 
    

    git commit 然后 git push -f origin &lt;branch-name&gt; 会让你开心。

    【讨论】:

      【解决方案2】:

      我遇到了类似的问题,结果发现我正在解决与 --ours 的冲突,而我本应使用 --theirs

      原因是--oursmerge 中的您的 更改,但在rebase 中是--theirs,因为 git 有效地删除了您的提交并重放它们的副本。

      因此,当您使用 rebase 解决与您的版本的冲突时,请执行以下操作:

      git checkout --theirs some.file git add some.file

      但是当使用merge 解决与您的版本的冲突时,请执行以下操作:

      git checkout --ours some.file git add some.file

      【讨论】:

        【解决方案3】:

        当您执行 git rebase 操作时,您通常会四处移动提交。因此,您可能会遇到引入合并冲突的情况。这意味着您的两次提交修改了同一文件中的同一行,而 Git 不知道要应用哪个更改。

        在您使用 git rebase 重新排序和操作提交后,如果发生合并冲突,Git 将通过打印到终端的以下消息告诉您:

        error: could not apply fa39187... something to add to patch A
        
        When you have resolved this problem, run "git rebase --continue".
        If you prefer to skip this patch, run "git rebase --skip" instead.
        To check out the original branch and stop rebasing, run "git rebase --abort".
        Could not apply fa39187f3c3dfd2ab5faa38ac01cf3de7ce2e841... Change fake file
        

        在这里,Git 告诉您哪个提交导致了冲突 (fa39187)。您有三个选择:

        • 您可以运行 git rebase --abort 以完全撤消变基。 Git 会将您返回到调用 git rebase 之前的分支状态。
        • 您可以运行 git rebase --skip 以完全跳过提交。这意味着不会包含由有问题的提交引入的任何更改。您很少会选择此选项。
        • 您可以解决冲突。

        要解决冲突,您可以关注the standard procedures for resolving merge conflicts from the command line。完成后,您需要调用 git rebase --continue 以便 Git 继续处理其余的变基。

        【讨论】:

          【解决方案4】:

          我不关心提交的历史。

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

          要基本上就地做到这一点--squash,你可以这样做:

          git branch -m feature feature-old
          git checkout master -b feature
          git merge --squash feature-old
          

          解决所有冲突后(一次),您将在 feature 上创建一个以 master 作为父级的提交。

          话虽如此,我很喜欢记录历史。一定要先试试rerere。您也可以尝试使用就地 rebase --interactive(例如 git rebase -i $(git merge-base HEAD master))来压缩修复型提交,而不会完全消除所有离散提交。

          【讨论】:

            【解决方案5】:

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

            ...--o--*--A--B          <-- master
                     \
                      C--D--...--Z   <-- feature
            

            这就是您现在所拥有的:名称master 指向提示提交 B(每个单字母或o* 代表一个提交)。每个提交都指向(左)其先前的提交。两个提交,AB,仅在 master 上。一堆提交只在feature 上,即CZ 这里。提交 * 和所有 earlier(更左)提交都在 both 分支上。

            git rebase 所做的是通过从提交Z 以及从master 的尖端向后工作来定位提交*。然后它知道它需要复制 提交 C-Z。副本将在 master 之后立即开始。如果我们使用C' 命名C 的副本,D' 命名D 的副本,依此类推,最终的 graph 将如下所示:

                            C'-D'-...-Z'   <-- feature
                           /
            ...--o--*--A--B                <-- master
                     \
                      C--D--...--Z         [abandoned]
            

            我认为您已经意识到,通过将每个提交(这是一个完整的快照)转换为一组更改,每次提交一个副本。为了得到C 中的改变,Git 做了:

            git diff <hash-of-*> <hash-of-C>
            

            然后Git 尝试将此更改应用到B 中的快照,但它并不容易应用,因此Git 尝试进行合并:它将*B 进行比较,发现它应该更改@987654348 @到&lt;div id="bar"&gt;,据此;但它应该根据*-vs-C 更改&lt;div id="foo"&gt; &lt;div id="fubar"&gt;。这是第一次合并冲突。

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

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

            然后 Git 继续复制 D,通过区分 DC 来获取补丁。

            这一次,应该没有&lt;div id="foo"&gt;&lt;div id="fubar"&gt;的变化,所以你不应该在这里遇到合并冲突。要确定答案,请尝试git show-ing commit D,同样将其与C 进行比较,产生差异。

            但是,您可能会被空白更改或类似情况所困扰。值得仔细查看每个 git diff 输出,如果您正在使用这些(CRLF 转换),请检查诸如行尾属性之类的内容。行尾内容通常会影响每个文件中的每一行,但您可能会遇到单行问题的情况,这取决于谁使用什么编辑器。

            我怀疑一个更可能的问题:git diff 正在同步错误的行。它会找到一些匹配的琐碎内容,例如读取} 的行,并使用这些内容来确定两个文件重新同步,然后挑选出“错误的更改”。如果是这种情况,解决方法(如果有的话)是指示 Git 使用更智能的 diff。特别是,patience 差异尝试不在琐碎的行上进行同步,而是仅在重要的(即非重复出现的)行上进行同步。这实际上可能有帮助,也可能没有帮助——在你的提交上运行 git diff --diff-algorithm=patience(或 git show 具有相同的参数)可能会告诉你。能否通过 rebase 使用不同的 diff 算法取决于您的 Git 版本。

            除了 Git 似乎重复更改的奥秘之外,当它应该在 C-vs-D 中只有 其他 更改时,您可以做一件事 提供帮助的方法是使用 git rerere 让 Git re - 使用 recorded re 解决方案(因此得名)。基本上,当 Git 遇到合并冲突时,如果启用了 rerere,Git 会将冲突部分写入其数据库,然后当您 git add 解决的文件时,Git 会写入解决方案(与原始冲突配对)。然后,下次 Git 遇到合并冲突时,它会检查保存的 rerere 数据:如果冲突是针对同一个补丁的,它会提取记录的分辨率,并在不与您交互的情况下使用它。

            您确实可以通过在提交* 之上重新设置feature(使用交互式rebase)来将部分或全部功能提交压缩在一起。由于这些补丁不会与自身发生冲突——至少只要它们“按顺序”播放——这可以让您减少需要解析的提交数量。是否应该由你自己决定:一般来说,如果你正在变基,无论如何你都会得到新的替换提交,所以你最好让新的提交“尽可能漂亮”以供将来调试或其他代码探索。显然,最好有五个“做一些有趣的事情,但几乎是独立的”提交,而不是 50 个“做一件事情的片段,做另一个片段,修复前一个片段,再做一个片段,OK 那件事完成了 move接下来,哎呀修复了微小的错误,......”所以这些都是非常好的组合在一起的候选者。但是,通常有五个“做一件事”的提交比一个“做五件事”的提交要好:这意味着如果五个中有一个有错误,你可以修复那个而不用担心关于其他四个。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-06-06
              • 1970-01-01
              • 2011-12-16
              • 1970-01-01
              • 2018-10-14
              • 1970-01-01
              相关资源
              最近更新 更多