假设你有以下内容:
A-B-C
现在您的构建/测试失败了。应该将修复程序合并到A中。我当前的工作流程如下:
$ git commit -m "fixA"
A-B-C-fixA
$ git rebase -i A~1
将修复A的补丁合并到A中,结果为:
A'-B-C
有没有类似下面命令的功能:
A-B-C + (index with fix for A)
$ git commit -supperdupper A
结果:
A'-B-C
假设你有以下内容:
A-B-C
现在您的构建/测试失败了。应该将修复程序合并到A中。我当前的工作流程如下:
$ git commit -m "fixA"
A-B-C-fixA
$ git rebase -i A~1
将修复A的补丁合并到A中,结果为:
A'-B-C
有没有类似下面命令的功能:
A-B-C + (index with fix for A)
$ git commit -supperdupper A
结果:
A'-B-C
如果你只是想寻找解决早期提交问题的简单方法,请阅读问题!它解释了所有内容。但由于Elmarco正在寻求一种简洁的方法,所以我们来看看:
从Git 1.7.0开始,--autosquash
选项用于rebase
,可以实现您想要的功能。 还有--fixup
和--squash
选项用于commit
,可以使事情变得更加容易。通过一些别名,您甚至可以将整个过程变成一个单一的命令。
我建议升级到最新的Git,以获得最大的优势:
git/Documentation/RelNotes $ grep -i -A1 autosquash\\\|fixup *
1.7.0.txt: * "git rebase -i" learned new action "fixup" that squashes the change
1.7.0.txt- but does not affect existing log message.
--
1.7.0.txt: * "git rebase -i" also learned --autosquash option that is useful
1.7.0.txt: together with the new "fixup" action.
1.7.0.txt-
--
1.7.3.txt: * "git rebase -i" peeks into rebase.autosquash configuration and acts as
1.7.3.txt: if you gave --autosquash from the command line.
1.7.3.txt-
--
1.7.4.txt: * "git commit" learned --fixup and --squash options to help later invocation
1.7.4.txt- of the interactive rebase.
--
1.7.4.txt: * "git rebase --autosquash" can use SHA-1 object names to name which
1.7.4.txt: commit to fix up (e.g. "fixup! e83c5163").
1.7.4.txt-
我创建了一些别名,以便更轻松地使用git 1.7中添加的git commit --fixup
和git commit --squash
命令。将它们添加到您的~/.gitconfig
文件中:
[alias]
fixup = !sh -c 'REV=$(git rev-parse $1) && git commit --fixup $@ && git rebase -i --autosquash $REV^' -
squash = !sh -c 'REV=$(git rev-parse $1) && git commit --squash $@ && git rebase -i --autosquash $REV^' -
使用方法:
$ git commit -am 'bad commit'
$ git commit -am 'good commit'
$ git add . # Stage changes to correct the bad commit
$ git fixup HEAD^ # HEAD^ can be replaced by the SHA of the bad commit
糟糕的提交可能在几个提交之前。
我的当前git工作流程非常依赖于--fixup
/--squash
参数,因此我编写了一个新的git-fixup
命令,自动处理大部分繁琐的部分:
git fixup
显示修改过的文件,并将它们分组到最近修改同一文件的提交下面。git fixup -a
将所有这些更改作为--fixup
更改提交,并指定相应的“父”提交。git fixup -r
对所有fixup提交进行自动git rebase --autosquash
操作。很多更改只需要使用上述三个命令即可完成,不需要复制粘贴提交ID或查找正确的--fixup
目标。
git rebase --interactive <3rd last commit>
然后,您需要选择最后一次提交并压缩倒数第二次提交。您无法压缩历史记录中的最顶部提交。
我认为问题的根源在于git(以及版本控制一般)强制你按照变更序列思考,但是一个变更集或特性分支或者无论你称之为什么的相关变更的凝聚组通常不是逻辑上的顺序。代码编写的顺序是偶然的,不一定与阅读代码的顺序有关。
我没有解决方案,但我已经编写了一个Perl脚本来帮助自动化重写历史的过程。它类似于@MikaEloranta的Python脚本,当时我还没有看到它。
commit --fixup
和rebase --autosquash
很棒,但它们做得不够。当我有一个提交序列A-B-C
并且我在我的工作树中编写了更多的变更,这些变更属于其中一个或多个现有的提交时,我必须手动查看历史记录,决定哪些变更属于哪些提交,将它们暂存并创建fixup!
提交。但是git已经可以访问足够的信息来代替我完成所有这些操作。
对于git diff
中的每个块,脚本使用git blame
查找最后一次触及相关行的提交,并调用git commit --fixup
编写适当的fixup!
提交,从根本上做我之前手动完成的相同工作。
如果脚本无法将块解析为单个、明确的提交,则会将其报告为失败的块,您将不得不回到手动方法。如果您在两个不同的提交中两次更改了一行,则脚本将把该行的更改解析为这些提交中最近的一个,这可能并不总是正确的解决方案。在“正常形式”的特性分支中,您不应该在两个不同的提交中两次更改一行,每个提交应该呈现它所涉及的行的最终版本,以帮助审阅者。但是,在修复错误的分支中可能会发生这种情况,举个例子,行foo(bar());
可能会被提交A(将foo
重命名为fox
)和提交B(将bar
重命名为baz
)所触及。
git
中得到这样的功能。我很想看到一个工具,当交互式变基引入合并冲突时,它能够理解如何解决它。
git fixup <rev>
)已经有一段时间了。 - Frerich Raabe