重新设置 Git 合并提交

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4783599/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 09:55:23  来源:igfitidea点击:

Rebasing a Git merge commit

gitmergerebasegit-rebasegit-rewrite-history

提问by jipumarino

Take the following case:

看下面的案例:

I have some work in a topic branch and now I'm ready to merge back to master:

我在一个主题分支中有一些工作,现在我准备合并回 master:

* eb3b733 3     [master] [origin/master]
| * b62cae6 2   [topic]
|/  
* 38abeae 1

I perform the merge from master, resolve the conflicts and now I have:

我从 master 执行合并,解决冲突,现在我有:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | eb3b733 3                     [origin/master]
|/  
* 38abeae 1

Now, the merge took me some time, so I do another fetch and notice that the remote master branch has new changes:

现在,合并花了我一些时间,所以我又做了一次 fetch 并注意到远程 master 分支有新的变化:

*   8101fe3 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
| | * e7affba 4                   [origin/master]
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

If I try 'git rebase origin/master' from master, I'm forced to resolve all conflicts again, and I also lose the merge commit:

如果我尝试从 master 执行 'git rebase origin/master',我将被迫再次解决所有冲突,并且我也会丢失合并提交:

* d4de423 2       [master]
* e7affba 4       [origin/master]
* eb3b733 3
| * b62cae6 2     [topic]
|/  
* 38abeae 1

Is there a clean way to rebase the merge commit so I end up with a history like the one I show below?

有没有一种干净的方法来重新设置合并提交,所以我最终会得到像下面显示的那样的历史记录?

*   51984c7 Merge branch 'topic'  [master]
|\  
| * b62cae6 2                     [topic]
* | e7affba 4                     [origin/master]
* | eb3b733 3
|/  
* 38abeae 1

采纳答案by siride

There are two options here.

这里有两个选项。

One is to do an interactive rebase and edit the merge commit, redo the merge manually and continue the rebase.

一种是进行交互式变基并编辑合并提交,手动重做合并并继续变基。

Another is to use the --rebase-mergesoption on git rebase, which is described as follows from the manual: "By default, a rebase will simply drop merge commits from the todo list, and put the rebased commits into a single, linear branch. With --rebase-merges, the rebase will instead try to preserve the branching structure within the commits that are to be rebased, by recreating the merge commits. Any resolved merge conflicts or manual amendments in these merge commits will have to be resolved/re-applied manually."

另一种方法是使用--rebase-mergeson 选项git rebase,手册中对它的描述如下:“默认情况下,rebase 将简单地从待办事项列表中删除合并提交,并将重新提交的提交放入单个线性分支中。使用 --rebase-合并时,rebase 将尝试通过重新创建合并提交来尝试保留要重新创建的提交中的分支结构。这些合并提交中任何已解决的合并冲突或手动修改都必须手动解决/重新应用。”

回答by Ivan Naydonov

Ok, that's an old question and it already have accepted answer by @siride, but that answer wasn't enough in my case, as --preserve-mergesforces you to resolve all conflicts second time. My solution based on the idea by @Tobi Bbut with exact step-by-step commands

好的,这是一个老问题,它已经接受了 的答案@siride,但在我的情况下,该答案还不够,因为会--preserve-merges迫使您第二次解决所有冲突。我的解决方案基于这个想法,@Tobi B但具有精确的分步命令

So we'll start on such state based on example in the question:

因此,我们将根据问题中的示例开始这种状态:

*   8101fe3 Merge branch 'topic'  [HEAD -> master]
|\  
| * b62cae6 2                     [topic]
| |
| | * f5a7ca8 5                   [origin/master]
| | * e7affba 4
| |/  
|/|   
* | eb3b733 3
|/  
* 38abeae 1

Note that we have 2 commits ahead master, so cherry-pick wouldn't work.

请注意,我们在 master 之前有 2 个提交,因此cherry-pick 不起作用。

  1. First of all, let's create correct history that we want:

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    We use --preserve-mergesto save our merge commit in history. We use --strategy=oursto ignore all merge conflicts as we don't care about what contents will be in that merge commit, we only need nice history now.

    History will looks like that (ignoring master):

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. Let's get correct index now.

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    

    We may get some additional merge conflicts here, but that's would only be conflicts from files changed between 8101fe3and f5a7ca8, but not includes already resolved conflicts from topic

    History will looks like this (ignoring correct-history):

    *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
    |\  
    * | f5a7ca8 5                   [origin/master]
    * | e7affba 4
    | *   8101fe3 Merge branch 'topic'
    | |\  
    | | * b62cae6 2                     [topic]
    |/ /
    * / eb3b733 3
    |/  
    * 38abeae 1
    
  3. The last stage is to combine our branch with correct history and branch with correct index

    git reset --soft correct-history
    git commit --amend
    

    We use reset --softto reset our branch (and history) to correct-history, but leave index and working tree as is. Then we use commit --amendto rewrite our merge commit, that used to have incorrect index, with our good index from master.

    In the end we will have such state (note another id of top commit):

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  1. 首先,让我们创建我们想要的正确历史记录:

    git checkout -b correct-history # create new branch to save master for future
    git rebase --strategy=ours --preserve-merges origin/master
    

    我们用来--preserve-merges在历史中保存我们的合并提交。我们--strategy=ours过去常常忽略所有合并冲突,因为我们不关心合并提交中将包含哪些内容,我们现在只需要好的历史记录。

    历史看起来像这样(忽略主人):

    *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    
  2. 现在让我们得到正确的索引。

    git checkout master # return to our master branch
    git merge origin/master # merge origin/master on top of our master
    

    我们可能会在这里遇到一些额外的合并冲突,但这只会是来自8101fe3和之间更改的文件的冲突f5a7ca8,但不包括已经解决的冲突topic

    历史看起来像这样(忽略正确的历史):

    *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
    |\  
    * | f5a7ca8 5                   [origin/master]
    * | e7affba 4
    | *   8101fe3 Merge branch 'topic'
    | |\  
    | | * b62cae6 2                     [topic]
    |/ /
    * / eb3b733 3
    |/  
    * 38abeae 1
    
  3. 最后一个阶段是将我们的分支与正确的历史和分支与正确的索引结合起来

    git reset --soft correct-history
    git commit --amend
    

    我们使用reset --soft将我们的分支(和历史)重置为更正历史,但保持索引和工作树原样。然后我们使用commit --amend来自 master 的良好索引来重写我们的合并提交,该提交曾经有不正确的索引。

    最后我们会有这样的状态(注意另一个顶部提交的 id):

    *   13e6d03 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    * | f5a7ca8 5                     [origin/master]
    * | e7affba 4
    * | eb3b733 3
    |/  
    * 38abeae 1
    

回答by Claude Peloquin

Given that I just lost a day trying to figure this out and actually found a solution with the help of a coworker, I thought I should chime in.

鉴于我刚刚花了一天时间试图解决这个问题,实际上在同事的帮助下找到了解决方案,我想我应该插话说。

We have a large code base and we have to deal with 2 branch heavily being modified at the same time. There is a main branch and a secondary branch if you which.

我们有一个庞大的代码库,我们必须同时处理 2 个被大量修改的分支。如果您选择哪个,则有一个主分支和一个辅助分支。

While I merge the secondary branch into the main branch, work continues in the main branch and by the time i'm done, I can't push my changes because they are incompatible.

当我将辅助分支合并到主分支时,主分支中的工作仍在继续,当我完成时,我无法推送我的更改,因为它们不兼容。

I therefore need to "rebase" my "merge".

因此,我需要“重新设定”我的“合并”。

This is how we finally did it :

这就是我们最终做到的:

1) make note of the SHA. ex.: c4a924d458ea0629c0d694f1b9e9576a3ecf506b

1) 记下 SHA。例如:c4a924d458ea0629c0d694f1b9e9576a3ecf506b

git log -1

2) Create the proper history but this will break the merge.

2)创建正确的历史记录,但这会破坏合并。

git rebase -s ours --preserve-merges origin/master

3) make note of the SHA. ex.: 29dd8101d78

3) 记下 SHA。例如:29dd8101d78

git log -1

4) Now reset to where you were before

4)现在重置到你以前的位置

git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard

5) Now merge the current master into your working branch

5) 现在将当前的 master 合并到你的工作分支中

git merge origin/master
git mergetool
git commit -m"correct files

6) Now that you have the right files, but the wrong history, get the right history on top of your change with :

6) 现在您拥有正确的文件,但错误的历史记录,在您的更改之上获取正确的历史记录:

git reset 29dd8101d78 --soft

7) And then --amend the results in your original merge commit

7) 然后 --amend 原始合并提交中的结果

git commit --amend

Voila!

瞧!

回答by Antoine Pelisse

It looks like what you want to do is remove your first merge. You could follow the following procedure:

看起来您想要做的是删除您的第一个合并。您可以按照以下步骤操作:

git checkout master      # Let's make sure we are on master branch
git reset --hard master~ # Let's get back to master before the merge
git pull                 # or git merge remote/master
git merge topic

That would give you what you want.

那会给你你想要的。

回答by Tobi B

  • From your merge commit
  • Cherry-pick the new change which should be easy
  • copy your stuff
  • redo the merge and resolve the conflicts by just copying the files from your local copy ;)
  • 从你的合并提交
  • Cherry-pick 应该很容易的新变化
  • 复制你的东西
  • 只需从本地副本中复制文件即可重做合并并解决冲突;)