在保留对master的引用的同时,使用git从master将一系列小合并压缩到我的分支中? [英] Squashing a sequence of small merges from master into my branch with git while keeping reference to master?

查看:79
本文介绍了在保留对master的引用的同时,使用git从master将一系列小合并压缩到我的分支中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常复杂的合并工作.问题的部分原因是我花了太多时间,所以要合并到我的分支中的更改量真是太可怕了.

I had a very complicated merge to do. Part of the problem lay that I let too much time pass by so the amount of changes to incorporate into my branch was monstrous.

为了使事情变得更容易,我选择先执行git merge origin/master~20,然后执行git merge origin/master~17git merge origin/master~15等,这样我就可以零碎地解决冲突,而不必一次全部解决.

To make things easier, I opted by doing git merge origin/master~20, then git merge origin/master~17, git merge origin/master~15, etc, so I could do the conflict resolutions in a piecemeal fashion instead of having to take it all at once.

问题在于这会导致我想摆脱的日志历史记录受到污染.合并所有这些提交同时仍使生成的提交同时指向我的分支和主服务器的最佳方法是什么?

The problem is tha this lead to a pollution of the log history that I would like to get rid of. What is the best approach to merge all these commits while still keeping the resulting commit pointing to both my branch and master?

我通常使用git reset --soft进行压缩,但这不会留下对master分支的引用.我也尝试git rebase -i --preserve-merges,但收到了"Refusing to squash a merge"错误消息.

I usually squash by using git reset --soft but that would not leave a reference to the master branch. I also tried to git rebase -i --preserve-merges but I got "Refusing to squash a merge" error messages.

我应该如何进行?

推荐答案

让我这样描述您的情况:您具有想要的合并结果-源树,但没有您想要的历史记录会导致此结果.

Let me describe your situation this way: You have the merge result you want—the source tree—but not the history you want that leads to this result.

正如 VonC将其放在其他地方,而您尝试自己尝试时,git reset --soft通常是 >答案.您进行软重置,然后进行新的提交.如果您现在只能进行 merge 提交,那仍然是答案.

As VonC has put it elsewhere, and you attempted yourself, git reset --soft usually is the answer. You do the soft reset, then make a new commit. If only you could make a merge commit at this point, it would still be the answer.

不使用git rerere可以通过三种简单的方法来执行此操作.一种是通过作弊,一种方式是记录在案的作弊",因此可能是正确的方式. (我的首选方法是中间方法,因为它又短又甜,但是显然是作弊的,所以有一天可能会停止工作.)

There are three easy ways to do this without git rerere. One is by cheating, and one of the ways is "documented cheating" and is therefore probably the right way. (My preferred method is middle one, as it's short and sweet, but it clearly is cheating, so it might stop working someday.)

请注意,此处的命令序列假定您位于存储库的顶层(特别是下面的git rmgit checkout步骤是指.表示一切").我还使用$startpoint进行提交,之后要进行合并,并使用$other引用另一个分支名称或提交ID(您要进行git merge的提交).

Note that the command sequence here assumes you are in the top level of your repository (in particular the git rm and git checkout steps below refer to . to mean "everything"). I also use $startpoint for the commit after which you want to have your merge, and $other to refer to the other branch-name or commit ID (the one you want to git merge).

  1. 保存最终结果的ID(我们需要 tree ,但是标准工具使其最简单地引用提交,这也很好用):

  1. Save the ID of the final result (we want the tree, but the standard tools make it easiest to just refer to the commit, which also works fine):

$ git tag temp-save-result

(或使用剪切粘贴或引用日志保存它;在这里我只是为了简单起见显示一个标签).

(or use cut-and-paste or the reflog to save it; I show a tag just for simplicity here).

重置.最好是--hard,而不是--soft:

Reset. This might as well be --hard, rather than --soft:

$ git reset --hard $startpoint

  • 运行合并,该合并将因冲突而失败.忽略冲突,并删除整个索引和工作树.我们不希望发生冲突的合并或到目前为止的任何临时结果,因为我们拥有正确的 结果在其他地方.

  • Run the merge, which will fail with conflicts. Ignore the conflicts and remove the entire index and work-tree. We don't want the conflicted merge, or any of the temporary results so far, because we have the proper results elsewhere.

    $ git merge $other
    $ git rm -r .
    

    ((如果您有一些自定义的合并工具会留下小滴,您可能也希望从这里将其清除到工作树中,尽管它们不会影响任何重要的事情:它们只会使您的工作树变得混乱不堪) ).

    (if you have some custom merge tools that leave droppings behind, you might want to clean those out of the work tree here as well, although they won't affect anything important: they'll just be cluttering up your work tree).

    提取步骤1中保存的工作树,并提交结果:

    Extract the work-tree saved in step 1, and commit the result:

    $ git checkout temp-save-result -- .
    $ git commit
    

  • 此提交结束了合并,合并的 tree 来自您在步骤1中保存的树.您现在可以删除标记:

    This commit concludes the merge, whose tree comes from the tree you saved in step 1. You can now delete the tag:

    $ git tag -d temp-save-result
    

    方法2:作弊

    git commit进行新提交时,如果.git/MERGE_HEAD存在,则进行合并提交. MERGE_HEAD文件包含第二个提交的ID,即正在合并的 other remote --theirs.

    Method 2: cheat

    When git commit makes a new commit, it makes a merge commit if .git/MERGE_HEAD exists. The MERGE_HEAD file contains the ID of the second commit, i.e., the other or remote or --theirs that is being merged-in.

    因此,我们只需像往常一样简单地进行软重置,然后添加合并ID,然后提交. (注意:我最近还没有尝试过,Git可能还想要.git/MERGE_MSG.准备调整作弊技巧,或者直接进入方法3.)

    So, we simply do a soft reset as usual, then add the merge ID, then commit. (NB: I have not tried this lately, and Git might also want .git/MERGE_MSG. Be prepared to need to tweak the cheat, or just move on to method 3.)

    $ git reset --soft $startpoint
    $ git rev-parse $other > .git/MERGE_HEAD
    $ git commit
    

    第一个命令是我们通常的git reset --soft步骤,第二个命令是Git,它表示我们正在解决一个有冲突的合并(索引已全部解析,因此我们必须在该步骤中完成),而git commit现在提交合并.

    The first command is our usual git reset --soft step, the second lies to Git to say that we're resolving a conflicted merge (and the index is all resolved, so we must be done with that step), and the git commit now commits the merge.

    创建一个实际提交对象的命令git commit毫无疑问,只是一个在末尾运行它的shell脚本-git commit-tree.它要求:

    The command that makes an actual commit object—git commit was no doubt once just a shell script that ran it near the end—is git commit-tree. It requires:

    • 包含所需树的树对象
    • 提交消息(它将从stdin中读取一条,但是您可能应该使用-m-F)
    • 新提交的父代的父代ID
    • a tree object that contains the desired tree
    • a commit message (it will read one from stdin, but probably you should use -m or -F)
    • the parent IDs for the parents of the new commit

    它将新的提交对象写入存储库,并打印出对象的哈希ID.

    and it writes the new commit object to the repository, and prints out the object's hash ID.

    我们已经有树了!由于是当前提交,因此其ID为HEAD^{tree}(使用 gitrevisions语法).我们也有两个父ID.我们需要的只是消息:

    We already have the tree! Since it's the current commit, its ID is HEAD^{tree} (using gitrevisions syntax). We have the two parent IDs as well. All we need is the message:

    $ tmp=$(git commit-tree -p $startpoint -p $other -m 'merge msg' HEAD^{tree})
    

    一旦有了提交ID,我们只需在当前分支中git reset --hard指向它即可:

    Once we have the commit ID we just need to git reset --hard our current branch to point to it:

    $ git reset --hard $tmp
    

    (当然,您可以使用$(...)而不是第二个命令中的$tmp将两者合并为一个大命令,尽管这假定您的git commit-tree命令可以工作:最好针对个人情况执行两个步骤如果愿意,可以通过剪切和粘贴哈希ID来省略$tmp变量和相应的shell $(...)语法,还可以放入俗气的临时提交消息,然后使用git commit --amend重置后:--amend选项也适用于合并提交.)

    (Of course, you can combine the two into one big command using $(...) instead of $tmp in the second command, although that assumes your git commit-tree command will work: it's probably better to do two steps for personal comfort. You can omit the $tmp variable, and the corresponding shell $(...) syntax, by cutting and pasting the hash ID, if you like that better. And, you can put in a cheesy temporary commit message, then edit it with git commit --amend once you have reset to it: the --amend option works on merge commits too.)

    这篇关于在保留对master的引用的同时,使用git从master将一系列小合并压缩到我的分支中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆