【发布时间】:2012-12-26 17:28:47
【问题描述】:
我将一个大型项目的上游与我的本地 git 存储库合并。在合并之前,我有少量易于阅读的历史记录,但在合并之后,大量历史记录现在在我的仓库中。我不需要上游仓库的所有历史提交。
在此上游合并之后,我想保留其他提交。如何将所有从上游合并的历史压缩到一个提交中,同时保留上游合并后所做的提交?
【问题讨论】:
我将一个大型项目的上游与我的本地 git 存储库合并。在合并之前,我有少量易于阅读的历史记录,但在合并之后,大量历史记录现在在我的仓库中。我不需要上游仓库的所有历史提交。
在此上游合并之后,我想保留其他提交。如何将所有从上游合并的历史压缩到一个提交中,同时保留上游合并后所做的提交?
【问题讨论】:
使用此处找到的策略从主分支进行多次合并后,我能够压缩多个提交: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
【讨论】:
我最终使用的解决方案是手动重新创建历史记录。我这样做主要是因为我不想花太多时间寻找一个优雅的解决方案,而且没有太多历史记录(大约 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>
【讨论】:
几个选项供您选择:
不完全符合您的要求,但可能是一个不错的选择,而且容易得多。这使您可以像平常一样使用 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
如果上游的“新功能”提交同样是大量的提交,我们也可以重复这个过程来压缩它。
【讨论】:
没有办法做到这一点,因为您将无法与该远程存储库或同一项目的任何其他内容再次推送或合并。压缩时,您正在更改历史记录,从而导致您的存储库和远程存储库之间的 sha1-hash 不同。
您将不得不忍受庞大的历史。
【讨论】: