修剪Git提交/压缩Git历史

我每隔几分钟检查我的代码到一个Git分支,最后的评论就是“一切都破了再开始”和其他荒谬的事情。

然后,每隔几分钟/几小时/天,我就会认真地提交一个真正的评论,例如“第三次修正了错误#22.55”。 我怎样才能分开这两个概念? 我希望能够删除所有我的频繁提交,只留下严重的提交。

现在编辑答案 (在本文的后半部分)新的Git1.7修复! 动作和 – --autosquash选项快速提交重新sorting和消息编辑。


首先是经典的压缩过程,就像在Git1.7之前所做的那样。
(Git1.7具有相同的过程,只有通过自动提交重新sorting的可能性,而不是手动重新sorting,并通过更干净的挤压消息,速度更快)

我希望能够删除所有我的频繁签证,只留下严重的。

这被称为压制提交
在这个Git就绪的文章中,你有一个很好的例子:“清理”
(注意: 自2007年9月以来 ,rebase交互function一直在使用 ,并允许压缩或拆分或删除或重新sorting提交:请参阅GitPro页面 )

谨慎的说法:只对未被推送到外部存储库的提交执行此操作。 如果其他人已经根据您要删除的提交进行工作,则可能会发生很多冲突。 只要不与其他人共享,就不要重写历史logging。

替代文字http://www.gitready.comhttp://img.dovov.comsquash1.png

如果把最后4次提交包装在一起,会更快乐

 $ git rebase -i HEAD~4 pick 01d1124 Adding license pick 6340aaa Moving license into its own file pick ebfd367 Jekyll has become self-aware. pick 30e0ccb Changed the tagline in the binary, too. # Rebase 60709da..30e0ccb onto 60709da # # Commands: # p, pick = use commit # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # 

使用头HEAD〜4的最后四个提交来重新HEAD~4
我们只是将所有东西压缩到一个提交。
所以,把文件的前四行改成这个就行了:

 pick 01d1124 Adding license squash 6340aaa Moving license into its own file squash ebfd367 Jekyll has become self-aware. squash 30e0ccb Changed the tagline in the binary, too. 

基本上,这告诉Git将所有四个提交合并到列表中的第一个提交。 一旦完成并保存,另一个编辑器popup如下:

 # This is a combination of 4 commits. # The first commit's message is: Adding license # This is the 2nd commit message: Moving license into its own file # This is the 3rd commit message: Jekyll has become self-aware. # This is the 4th commit message: Changed the tagline in the binary, too. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i nor -o; assuming --only paths... # Not currently on any branch. # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: LICENSE # modified: README.textile # modified: Rakefile # modified: bin/jekyll # 

由于我们合并了这么多的提交,所以Git允许您根据进程中涉及的其他提交来修改新提交的消息。 按照您认为合适的方式编辑消息,然后保存并退出。
一旦完成,你的提交已经成功地被压扁了!

 Created commit 0fc4eea: Creating license file, and making jekyll self-aware. 4 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 LICENSE Successfully rebased and updated refs/heads/master. 

如果我们再看历史

替代文字http://www.gitready.comhttp://img.dovov.comsquash2.png


注意:为了“ 压缩 ”目的, Git1.7 (2010年2月)推出了两个新元素(如Dustin在评论中提到的):

  • git rebase -i ”学到了新的动作“ fixup ”,它压缩了变化,但不影响现有的日志信息。
  • git rebase -i ”也学到了 – --autosquash选项,与新的“fixup”操作一起使用。

这两个(fixup行动和 – --autosquash选项)在这个Thechnosorcerynetworking博客条目中说明 。 自2009年6月份以来,这些function一直在进行烹调,并在去年12月进一步辩论

fixup动作或指令是用来压扁你在rebase --interactive的提交编辑列表中手动重新sorting的提交,而忽略第二个提交消息,这将使得消息编辑步骤更快(你可以保存它:压扁的提交将只有第一个提交信息)
由此产生的提交消息将只是第一次提交。

  # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message 

--autosquash选项是为你自动进行提交重新sorting的过程:

如果你知道你想要压缩什么,你可以提交一个“ squash! $other_commit_subject squash! $other_commit_subject “。 然后,如果您运行@git rebase --interactive --autosquash commitish@ ,则该行将自动设置为压扁,并放置在$ other_commit_subject主题的提交下方。

(实际上, squash!只能使用另一个提交信息的开始

 $ vim Foo.txt $ git commit -am "Change all the 'Bar's to 'Foo's" [topic 8374d8e] Change all the 'Bar's to 'Foo's 1 files changed, 2 insertions(+), 2 deletions(-) $ vim Bar.txt $ git commit -am "Change all the 'Foo's to 'Bar's" [topic 2d12ce8] Change all the 'Foo's to 'Bar's 1 files changed, 1 insertions(+), 1 deletions(-) $ vim Foo.txt $ git commit -am "squash! Change all the 'Bar's" [topic 259a7e6] squash! Change all the 'Bar's 1 files changed, 2 insertions(+), 1 deletions(-) 

看到? 这里第三次提交只使用第一个提交消息的开头。
一个rebase --interactive --autosquash会把被压扁的提交移动到相关的那个之下:

 pick 8374d8e Change all the 'Bar's to 'Foo's squash 259a7e6 squash! Change all the 'Bar's pick 2d12ce8 Change all the 'Foo's to 'Bar's 

消息版本将是:

 # This is a combination of 2 commits. # The first commit's message is: Change all the 'Bar's to 'Foo's # This is the 2nd commit message: squash! Change all the 'Bar's 

默认情况下,您将保持提交消息中logging的压缩操作。
但是,修复! 指令,你可以在提交消息中保持压缩状态“不可见”,同时还可以通过使用--autosquash选项自动执行重新sorting(以及第二个提交消息基于你想要压缩的第一个提交的事实) )。

 pick 8374d8e Change all the 'Bar's to 'Foo's fixup cfc6e54 fixup! Change all the 'Bar's pick 2d12ce8 Change all the 'Foo's to 'Bar's 

该消息默认是:

 # This is a combination of 2 commits. # The first commit's message is: Change all the 'Bar's to 'Foo's # The 2nd commit message will be skipped: # fixup! Change all the 'Bar's 

注意fixup! 提交的消息已经被注释掉了。
你可以直接保存消息,原始的提交消息将被保留
当你意识到你忘记添加一个早期的提交的一部分,非常方便包括更改

现在,如果您想根据之前的提交进行修复或压缩Jacob Helwig (Technosorcery Networks博客条目的作者)build议使用以下别名:

 [alias] fixup = !sh -c 'git commit -m \"fixup! $(git log -1 --format='\\''%s'\\'' $@)\"' - squash = !sh -c 'git commit -m \"squash! $(git log -1 --format='\\''%s'\\'' $@)\"' - 

而为了做一个rebase互动,总是会受益于意图被压扁的提交的自动重新sorting:

 [alias] ri = rebase --interactive --autosquash 

使用软重置而不是重新压缩GIT历史

我认为VonC答案的长度是字面意思,就是说git rebase是多么复杂。 这是我对我的一个问题的另一个答案的延伸。

  1. 你有一个分支机构ticket-201 ,你从master分支。 你想假装从ticket-201提交的所有提交都没有发生过,但是你完成了所有的工作。
  2. 软重置到分支点使用git reset --soft hash其中hash应该是一个提交散列在ticket-201的日志。
  3. 使用添加然后提交来提交您的更改。 现在分支历史将只有第一次提交和新的东西。

从不同分支的任意承诺看历史

使用重置,您可以重新编写历史logging,尽pipe您的编辑将失去拥有正确时间戳的魅力。 假设你不关心它(文件上的时间/date就足够了,也许?),或者如果你想提交提交,你可以按照下面的步骤:

  1. 签出一个新的分支在commit0 (假装这是一个散列): git checkout -b new-history commit0
  2. 现在你可以从commit5获得文件: git reset --hard commit5
  3. 切换回你的索引点: git reset --soft commit0
  4. 提交,这将是分支中的第二次提交。

这个想法简单,有效和灵活。

用南瓜代替

最近,我一直在另一个分公司工作,并使用squash 。 另一个分支叫做temp,然后我用git merge temp --squash把它引入真正的分支,并把它推到服务器端。

工作stream程就像这样,假设我在Ticket65252工作:

 git branch -d temp #remove old temp bbranch git checkout -b temp # work work work, committing all the way git checkout Ticket65252 git merge temp --squash git commit -m "Some message here" 

使用rebase优点 ? 方式较为复杂。

使用reset --hard优点 – reset --soft ,然后reset --soft 不那么容易混淆,而且容易出错。

使用git rebase -i来挑选和挤压你的提交。