【问题标题】:Git squash history after merge合并后的Git壁球历史
【发布时间】:2012-12-26 17:28:47
【问题描述】:

我将一个大型项目的上游与我的本地 git 存储库合并。在合并之前,我有少量易于阅读的历史记录,但在合并之后,大量历史记录现在在我的仓库中。我不需要上游仓库的所有历史提交。

在此上游合并之后,我想保留其他提交。如何将所有从上游合并的历史压缩到一个提交中,同时保留上游合并后所做的提交?

【问题讨论】:

    标签: git git-merge squash


    【解决方案1】:

    使用此处找到的策略从主分支进行多次合并后,我能够压缩多个提交:https://stackoverflow.com/a/17141512/1388104

    git checkout my-branch            # The branch you want to squash
    git branch -m my-branch-old       # Change the name to something old
    git checkout master               # Checkout the master branch
    git checkout -b my-branch         # Create a new branch
    git merge --squash my-branch-old  # Get all the changes from your old branch
    git commit                        # Create one new commit
    

    如果您需要将压缩的分支推送到您之前推送到的远程存储库,您将不得不强制更新,例如git push origin my-branch -f

    【讨论】:

      【解决方案2】:

      我最终使用的解决方案是手动重新创建历史记录。我这样做主要是因为我不想花太多时间寻找一个优雅的解决方案,而且没有太多历史记录(大约 30 次提交我必须手动合并)。

      所以,我在合并庞大的上游之前创建了一个分支:

      git checkout -b remove-history-fix <commit ID before merge>
      

      然后使用--squash 选项重新合并上游。

      git merge --squash <upstream tag>
      

      然后从旧分支(具有大量上游历史记录的分支)合并后手动挑选提交。

      git cherry-pick <commit ID>
      

      在所有这些提交合并到我的 remove-history-fix 分支后,我删除了包含上游历史记录的分支。

      git branch -D <upstream-history-branch>
      

      【讨论】:

      • 接受你的回答。 :)
      • 只是想补充一点,经过我自己的多次尝试,这个过程(或这个过程的复制粘贴变体)也是我能找到的唯一方法,以挤压不再处于尖端的东西合并提交后的分支会淹没分支时间线。这种合并对于需要很长时间才能进行 PR 的分支来说是必不可少的(另一方面,squash 是一种次要的奢侈品)。只需在任何初步合并之前添加你的 rebase -i 任务,它将为你省去以后的烦恼
      • 值得注意的是,通过进行 squash 合并,您不会记录实际的合并,因此可能会使您的上游提交成为孤立的(例如,如果您正在合并修补程序分支,然后删除上游没有标签的修补程序分支)。
      【解决方案3】:

      几个选项供您选择:

      限制日志记录

      不完全符合您的要求,但可能是一个不错的选择,而且容易得多。这使您可以像平常一样使用 git,但隐藏了所有您不想看到的东西(假设问题是历史记录使您的日志混乱而不是原始存储空间。我认为压缩分支中的合并不会如果您首先为合并操作获取了上游,则防止 git 包含来自上游的所有提交。)。

      在这种情况下,您可以进行正常的合并,但在记录时您需要将--first-parent 添加到命令中。

      例如,如果没有我可能拥有的选项(假设“sample more”1 到 3 实际上是更多的提交)

      $ git log --oneline
      0e151bf Merge remote-tracking branch 'origin/master' into nosquash
      f578cbb sample more 3
      7bc88cf sample more 2
      682b412 sample more 1
      fc6e1b3 Merge remote-tracking branch 'origin/master'
      29ed293 More stuff
      9577f30 my local change
      018cb03 Another commit
      a5166b1 Initial
      

      但是,如果我添加 --first-parent,它会清除此内容:

      $ git log --oneline --first-parent
      0e151bf Merge remote-tracking branch 'origin/master'
      fc6e1b3 Merge remote-tracking branch 'origin/master'
      9577f30 my local change
      018cb03 Another commit
      a5166b1 Initial
      

      请注意,在我分支后来自 master 的所有提交(“我的本地更改”是我的发散提交)都消失了。只有我所做的提交才会显示,包括我合并的时候。如果我在合并期间使用了更好的提交消息,我什至可能知道这批更改是什么。

      替换历史记录

      这是你问的。

      https://git-scm.com/book/en/v2/Git-Tools-Replace获得灵感

      我们在这里要做的是压缩遥控器的历史,从我们的角度用我们压缩的版本替换它们的历史,然后合并压缩的版本。

      在我的示例存储库中,上游添加的我尚未合并的修订是 682b412 "sample more 1" to origin/master (f578cbb "sample more 3")(虽然对于这个示例来说并不长,假装在那里是 50 次提交或介于两者之间)。

      我首先想要的是远程端的本地分支:

      git checkout -b squashing origin/master
      

      接下来,我要快点压扁它

      git reset --soft 682b412~
      git commit -m "Squashed upstream"
      

      注意波浪号~ 字符。这导致我们的分支位于我们想要压缩的范围内的第一个提交的父级,并且因为我们指定了--soft,我们的索引仍然是我们想要压缩的范围内的最后一个提交。提交行产生一个单一的提交,由我们的第一个到最后一个组成,包括在内。

      此时,origin/master 和 squashing 分支的树内容相同,但历史记录不同。

      现在,我们告诉 git,当它看到对 origin/master 的原始提交的引用时,使用我们压缩的提交来代替。使用git log 我可以看到新的“Squashed upstream”提交是 1f0bc14,所以我们这样做:

      git replace f578cbb 1f0bc14
      

      从这里开始,您的 git 将使用“压缩的上游”提交。

      回到我们原来的分支(如果它是“master”)

      git checkout master
      git merge f578cbb
      

      这似乎合并了原始主机 (f578cbb),实际上获取了 1f0bc14 的内容,但将其记录为具有 f578cbb 的父 SHA1

      我们不再需要 squashing 分支,因此您可以摆脱它。

      现在,假设上游添加了更多功能。在这个简单的示例中,在上游的 repo 中,日志可能会显示:

      84f5044 new feature
      f578cbb sample more 3
      7bc88cf sample more 2
      682b412 sample more 1
      29ed293 More stuff
      018cb03 Another commit
      a5166b1 Initia
      

      在我们获取上游之后,如果我们从我们的 repo 中查看它的日志,我们会看到:

      84f5044 new feature
      f578cbb squashed upstream
      29ed293 More stuff
      018cb03 Another commit
      a5166b1 Initial
      

      请注意它似乎也对我们造成了压缩历史记录,更重要的是,压缩的上游 SHA1 显示了上游历史记录中使用的那个(对他们来说,这实际上是“sample more 3”提交)。

      因此,合并继续正常工作

      git merge origin/master
      

      但我们没有这么杂乱的日志:

      4a9b5b7 Merge remote-tracking branch 'origin/master' for new feature
      46843b5 Merge remote-tracking branch 'origin/master'
      84f5044 new feature
      f578cbb squashed upstream
      fc6e1b3 Merge remote-tracking branch 'origin/master'
      29ed293 More stuff
      9577f30 my local change
      018cb03 Another commit
      a5166b1 Initial
      

      如果上游的“新功能”提交同样是大量的提交,我们也可以重复这个过程来压缩它。

      【讨论】:

        【解决方案4】:

        没有办法做到这一点,因为您将无法与该远程存储库或同一项目的任何其他内容再次推送或合并。压缩时,您正在更改历史记录,从而导致您的存储库和远程存储库之间的 sha1-hash 不同。

        您将不得不忍受庞大的历史。

        【讨论】:

        • 没有办法强制吗?我永远不需要退缩,将来我可以像以前一样做任何合并。
        • 这次是怎么合并的?该存储库的起源是什么?
        • 起源是从零开始的。我得到了一个 tar 文件,其中的来源可能从一个标签开始,然后进行了更改/添加,然后想要合并来自官方上游​​ repo 的更新/修复。合并需要大量的手动合并,这对我来说很好,因为我不会经常这样做。
        • 你能用你从上游合并的命令更新问题吗?
        猜你喜欢
        • 2010-11-30
        • 1970-01-01
        • 2017-09-23
        • 1970-01-01
        • 2014-07-27
        • 1970-01-01
        • 2011-12-03
        • 1970-01-01
        • 2018-04-02
        相关资源
        最近更新 更多