修剪Git提交/压缩Git历史

Dan*_*ark 66 git branch

我每隔几分钟就会将我的代码检查到一个Git分支中,并且评论最终会变成"Everything broken again again"和其他荒谬.

然后,每隔几分钟/小时/天,我会做一个真正的评论,比如"修正了第22,55号错误".我如何区分这两个概念?我希望能够删除所有我的频繁提交,然后离开严肃的提交.

Von*_*onC 98

现在编辑答案(在本条目的后半部分)新的Git1.7修正!--autosquash用于快速提交重新排序和消息编辑的操作和选项.


首先,经典压缩过程,如Git1.7之前所做的那样.
(Git1.7具有相同的过程,只有通过自动提交重新排序的可能性而不是手动重新排序,以及通过更清洁的压缩消息而更快)

我希望能够删除所有频繁的签到,只留下严肃的签到.

这称为压缩提交.
在这篇Git准备文章中你有一个很好的"comit清理"的例子:(
注意:自2007年9月以来出现了rebase交互功能,允许压缩或拆分或删除或重新排序提交:另请参阅GitPro页面)

需要注意的是:只在尚未推送到外部存储库的提交中执行此操作.如果其他人的工作基于您要删除的提交,则可能会发生许多冲突.如果已经与他人共享,请不要重写您的历史记录.

alt text http://www.gitready.com/images/squash1.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.
#
Run Code Online (Sandbox Code Playgroud)

使用HEAD与之相关的最后四次提交进行rebaseHEAD~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.
Run Code Online (Sandbox Code Playgroud)

基本上,这告诉Git将所有四个提交合并到列表中的第一个提交中.完成并保存后,会弹出另一个编辑器,其中包含以下内容:

# 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
#
Run Code Online (Sandbox Code Playgroud)

由于我们正在组合这么多提交,因此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.
Run Code Online (Sandbox Code Playgroud)

如果我们再看一下历史......

alt text http://www.gitready.com/images/squash2.png


注意:对于"提交挤压"的目的,Git1.7(2010年2月)引入了2个新元素(如Dustin在评论中所述):

  • " git rebase -i"学会了新的动作" fixup",它会压缩变化,但不会影响现有的日志消息.
  • " git rebase -i"还学习--autosquash了与新的"修正"动作一起使用的选项.

--autosquash这个Thechnosorcery Networks博客文章中都说明了(修正操作和选项).自去年6月以来,这些功能一直在烹饪,并在去年12月进一步辩论.

fixup操作或指令用于压缩您在a的提交编辑列表中手动重新排序的提交rebase --interactive,同时忽略第二个提交消息,这将使消息编辑步骤更快(您可以保存它:压缩的提交将具有首先提交消息)
生成的提交消息将只是第一个提交消息.

  # s, squash = use commit, but meld into previous commit
  # f, fixup = like "squash", but discard this commit's log message
Run Code Online (Sandbox Code Playgroud)

--autosquash选项是为您自动进行提交重新排序过程:

如果您知道要将某些内容压缩到哪个提交,则可以使用" squash! $other_commit_subject" 消息进行提交.然后,如果你运行@git rebase --interactive --autosquash commitish@,该行将自动设置为squash,并放置在$ 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(-)
Run Code Online (Sandbox Code Playgroud)

看到?这里第三个提交仅使用第一个提交消息的开头.
A 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
Run Code Online (Sandbox Code Playgroud)

消息版本将是:

# 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
Run Code Online (Sandbox Code Playgroud)

默认情况下,您将保持压缩操作记录在提交消息中.
但是有了修复!指令,您可以在提交消息中保持压缩"不可见",同时仍然可以从使用该--autosquash选项的自动提交重新排序中受益(以及您的第二个提交消息基于您想要被压扁的第一个提交的事实).

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
Run Code Online (Sandbox Code Playgroud)

默认情况下,该消息为:

# 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
Run Code Online (Sandbox Code Playgroud)

请注意,fixup!提交的消息已经注释掉了.
您可以按原样保存消息,并保留原始提交消息.
当您意识到忘记添加部分早期提交时,包含更改非常方便.

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

[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'\\'' $@)\"' -
Run Code Online (Sandbox Code Playgroud)

并且做一个rebase交互式,它将始终受益于意图被压缩的提交的自动重新排序:

[alias]
    ri = rebase --interactive --autosquash
Run Code Online (Sandbox Code Playgroud)

更新Git 2.18(2018年第二季度):" git rebase -i"有时会留下中间的" # This is a combination of N commits"消息,意味着在某些角落案件的最终结果中,编辑内部的人员消费已得到修复.

请参阅Johannes Schindelin()提交15ef693,提交dc4b5bc,提交e12a7ef,提交d5bc6f2(2018年4月27日).(由Junio C Hamano合并- -提交4a3bf32,2018年5月23日)dscho
gitster

rebase --skip:修复/壁球失败后清理提交消息

在一系列fixup/squash命令期间,交互式rebase构建带有注释的提交消息.如果这些命令中的至少一个是a,则将在编辑器中向用户呈现squash.

在任何情况下,在这样的fixup/squash链的最后一步中,最终将清除提交消息,删除所有那些中间注释.

但是,如果此类链中的最后一个fixup/squash命令因合并冲突而失败,并且如果用户随后决定跳过它(或将其解析为干净的工作树然后继续rebase),则当前代码无法清除提交消息.

此提交修复了该行为.

这次修复比眼睛更加复杂,因为它不仅仅是关于我们是git rebase --skip在进行修复还是壁球的问题.它还涉及从累积的提交消息中删除跳过的fixup/squash的提交消息.这也是关于我们是否应该让用户编辑最终提交消息的问题("链是否存在未被跳过的壁球?").

例如,在这种情况下,我们将要修复提交消息,但不能在编辑器中打开它:

pick  <- succeeds
fixup   <- succeeds
squash  <- fails, will be skipped
Run Code Online (Sandbox Code Playgroud)

这是新引入的current-fixups文件非常方便的地方.快速查看,我们可以确定是否有非跳过的壁球.我们只需要确保在跳过的fixup/squash命令方面保持最新.作为奖励,我们甚至可以避免不必要的提交,例如,当只有一次修复时,它失败了,并且被跳过了.

要仅修复最终提交消息未正确清理的错误,但没有修复其余的错误,将比一次性修复它更复杂,因此这个提交将多个问题集中在一起.


Git 2.19(Q8 2018)修复了一个错误:当git rebase -i告诉" "将两个或多个提交压缩成一个时,它会为每个提交标记日志消息及其编号.
它正确地称为第一个"第一次提交",但下一个是" commit #1",它是一个一个(!).

参见由Phillip Wood()提交dd2e36e(2018年8月15日).(由Junio C Hamano合并- -提交36fd1e8,2018年8月20日)phillipwood
gitster

rebase -i:修复壁球消息中的编号

提交e12a7ef(" rebase -i处理" <n>提交"与 GETTEXT_POISON",2018-04-27,Git 2.18的组合)改变了在压缩提交时标记单个提交消息的方式.
在这样做时,引入了回归,其中消息的编号是一个.此提交修复了该问题,并为编号添加了测试.


Dan*_*ark 27

使用软重置代替Rebase来压制GIT历史

我认为VonC答案的长度说明了数量上的复杂git rebase程度.这是我对我的问题的另一个答案的延伸.

  1. 你有一个分支的ticket-201分支master.你想假装所有的提交ticket-201从未发生过,但是你一次性完成了所有的工作.
  2. 软重置到分支点使用git reset --soft hashwhere hash应该是在ticket-201日志中的提交哈希.
  3. 使用add then commit提交更改.现在,分支历史记录将只有第一个提交,而新的提交具有新的提交.

从不同分支的任意提出来创造历史

使用重置,您可以根据需要重写历史记录,但您的编辑将失去拥有正确时间戳的魅力.假设你不关心它(你的文件的时间/日期就足够了,也许?),或者如果你想要随意提交提交,你可以按照以下步骤操作:

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

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


Dan*_*ark 7

使用壁球代替

最近,我一直在另一家分公司工作并使用squash.另一个分支称为temp,然后我用git merge temp --squash它将它带入推送到服务器的真实分支.

工作流程是这样的,假设我在工作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"
Run Code Online (Sandbox Code Playgroud)

使用优势rebase?方式不那么复杂.

使用的优点reset --hard然后reset --soft呢?减少混淆,减少错误.