我经常执行以下模式:
git commit -am "格式正确的消息"
- 再做一个小改动(我忘了)
git commit -am "foo"
git rebase -i
(并压缩foo
提交)- 编辑提交信息,删除“foo”
我可以使用单个命令或脚本执行步骤 3 到 5 吗?即提交所有内容并添加到之前的提交中。
最佳答案
在我提供下面的答案之前,请注意 git commit
有一个选项 --amend
,它(实际上):
- 执行软重置以移回一个提交,然后
- 做你想要的提交
这有效地用固定的提交替换了提交。 (“有效”是因为它正确处理了 merge 。)例如:
$ git commit -am "well formatted message"
现在提交图看起来像这样:
o - o - A <-- HEAD=yourbranch
然后你意识到你忘记了一些东西,所以你修复它并使用:
$ git commit -a --amend --no-edit
(--no-edit
避免调出编辑器)。 Git 有效地备份一个提交并进行新的提交 A'
:
A [abandoned, can only be found in reflog]
/
o - o - A' <-- HEAD=yourbranch
这通常是您在这里需要的工具。但是,如果您已经进行了第二次“良好”提交并且需要修复更早的历史记录,那么它就不起作用了。为此,请继续阅读。
自 git 版本 1.7.0(但通过 1.8.4 进行了一些修复,所以最好在 1.8.4 或更高版本中执行此操作),git rebase
有一个拼写为 --autosquash
的选项。 git commit
命令有 --fixup=
和 --squash=
选项与之配合使用,并且 git rebase
有一个配置项 rebase.autoSquash
,它默认打开 --autosquash
,因此您不必每次都指定它。
这是在 the git rebase
documentation 中描述的,但是有点晦涩:
--autosquash, --no-autosquash When the commit log message begins with "squash! ..." (or "fixup! ..."), and there is a commit whose title begins with the same ..., automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified, and change the action of the moved commit from pick to squash (or fixup). Ignores subsequent "fixup! " or "squash! " after the first, in case you referred to an earlier fixup/squash with git commit --fixup/--squash.
This option is only valid when the --interactive option is used.
它的工作方式非常简单,我认为一旦您了解了它的工作方式就会更有意义。交互式 rebase 脚本(它是一个 shell 脚本,如果您想查看详细信息,可以很容易地看到它是如何做到这一点的)首先收集提交列表,以及提交消息中的主题行。这与您在 git log --oneline
输出中看到的内容完全相同(这里是 git 的 git 树的片段):
88d5072 am --skip: revert changes introduced by failed 3way merge
19bf6c9 fsck: report errors if reflog entries point at invalid objects
d66ae59 fsck_handle_reflog_sha1(): new function
假设在 88d5072
之后,我们有一行内容是:
1234567 fixup! fsck_handle_reflog_sha1(): new function
这将是在 d66ae59
之后进行的提交(因为它在日志输出中更高);它的主题行与 d66ae59
完全匹配,除了前面的单词“fixup”(以及感叹号和空格)。
rebase
脚本所做的是将提交稍微打乱,以便 fixup!
提交紧跟在原始提交之后,并且通常会说 pick
,说 fixup
。然后,当它处理提交时,它像往常一样应用原始提交,并将修复作为修复应用,就像您已将提交移动到提交列表并将 pick
更改为 fixup
一样。
简而言之,它只是自动为您编辑 rebase “待办事项”列表。当交互式 rebase 编辑 session 开始时,您会看到修复。
当您将 git commit
与 --fixup=<...>
一起使用时,git 使提交消息以正确的方式读取以与 --autosquash
一起使用。您必须在提交时执行此操作,而不是在 rebase 时执行此操作。
因此,假设您没有使用原始场景(git commit --amend
运行良好),而是这样做了:
... edit ...
git commit ... # make slightly flawed commit A
... edit ...
git commit ... # make good commit B
... realize that there's a flaw in A; edit ...
$ git commit -a --fixup=HEAD^
这为您提供了一个三提交系列:
o - o - A - B - C <-- HEAD=yourbranch
提交 C
只是对 A
的修复。如果您运行 git log --oneline
,您会看到它具有 git rebase --autosquash
喜欢的形式;所以现在当你运行 git rebase -i --autosquash
时,你的 TODO 列表将有:
pick 1234567 well formatted message
fixup 3333333 fixup! well formatted message
pick fedcba9 another well formatted message
您只需退出编辑器即可获得所需内容。
关于git - git commit/rebase/squash 的单个命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32365421/