git - git commit/rebase/squash 的单个命令

标签 git

我经常执行以下模式:

  1. git commit -am "格式正确的消息"
  2. 再做一个小改动(我忘了)
  3. git commit -am "foo"
  4. git rebase -i(并压缩 foo 提交)
  5. 编辑提交信息,删除“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/

相关文章:

git diff 输出仅更改行

python - pip 连接失败 : cannot fetch index base URL http://pypi. python.org/simple/

git - 如何从 git log 输出中获取特定的 SHA

带有 a 的 git fatal error 路径没有意义

linux - 如何检查 GIT 是否已完全克隆存储库?

macos - Git 别名参数完成在 Zsh 中不起作用

git - 仅在本地分支或本地和远程分支上为新功能创建分支?

git - 如何防止开发人员将 master merge 到 Release 分支?

git - 使用Git将同一个项目不同版本的文件夹组织起来

ruby-on-rails - git clone heroku ssh 权限被拒绝