git:squash / fixup之前的提交

时间:2008-10-15 12:05:08

标签: git

假设你有:

A-B-C

现在你的构建/测试失败了。修复程序应合并到A. 我目前的工作流程是这样的:

$ git commit -m "fixA"

A-B-C-fixA

$ git rebase -i A~1

在A中压制fixA,结果是:

A'-B-C

是否有命令可以执行以下操作:

A-B-C + (index with fix for A)

$ git commit -supperdupper A 

结果:

A'-B-C

6 个答案:

答案 0 :(得分:20)

如果您只是想找到修复早期提交的简单解决方案,请阅读问题!它解释了一切。但是,由于Elmarco要求一个光滑的方式,我们在这里:

从Git 1.7.0开始,rebase有一个--autosquash选项,可以满足您的需求。 commit还有--fixup--squash个选项,可以让您更轻松。通过一些别名,您甚至可以将整个命令整合到一个命令中。

我建议升级到最新的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-

答案 1 :(得分:3)

我当前的git工作流是如此--fixup / --squash密集,我编写了一个新的git-fixup命令,可以自动处理大部分恼人的位:

  • git fixup显示已修改的文件,这些文件分组在触及相同文件的最新提交
  • git fixup -a将所有这些更改作为--fixup更改提交给相应的" parent"提交
  • git fixup -r为所有修复提交自动git rebase --autosquash

许多变化都是这样的,只有上面的三个命令足以完成工作,没有复制粘贴commit-id或通过git log读取以找到正确的{{ 1}}目标。

来源:https://github.com/ohmu/git-crust

答案 2 :(得分:2)

如果你想压缩最后两次提交,那么你必须调用

git rebase --interactive <3rd last commit>

然后,您需要选择最后一次提交并压缩倒数第二次提交。你不能压缩历史的最高提交。

答案 3 :(得分:2)

created some aliases可以更轻松地使用git 1.7中添加的git commit --fixupgit 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

糟糕的提交可能会有几次提交。

答案 4 :(得分:0)

如果您正在与其他人共享您正在进行更改的分支,那么您所做的事情是危险的。 在您的情况下,您重写提交A并在新A的基础上重新定位B和C,这是一个全新的对象。任何已经将旧A拉入其存储库的人最终可能会破坏他们的存储库,因为存储库中的历史记录会“神奇地”改变。他们的混蛋无法知道历史已被重写。

由于这个事实,Git开发人员故意不会这么做,因为您必须意识到执行此类操作的后果。

答案 5 :(得分:0)

我认为问题的根源在于git(通常是版本控制)迫使你根据变化的顺序进行思考,但是变更集或功能分支或者你称之为一组相关变化的一般情况通常都是不逻辑顺序。编写代码的顺序是偶然的,不一定与它应该被读取的顺序相关。

我没有解决方案,但我写了Perl script来帮助自动化重写历史记录的过程。它类似于@MikaEloranta的Python脚本,我在编写它时没有看到它。

commit --fixuprebase --autosquash很棒,但他们做得不够。当我有一系列提交A-B-C并且我在工作树中写了一些属于一个或多个现有提交的更改时,我必须手动查看历史记录,确定哪些更改属于哪些提交,暂存它们并创建fixup!提交。但是git已经可以访问足够的信息来为我做所有这些。

对于git diff中的每个块,脚本使用git blame查找最后触及相关行的提交,并调用git commit --fixup来编写相应的fixup!提交,基本上做我之前手动做的事情。

如果脚本无法将hunk解析为单个,明确的提交,则会将其报告为失败的hunk,并且您必须回退到该方法的手动方法。如果您在两次单独的提交中更改了两次,则脚本会将该行的更改解析为最新的提交,这可能并不总是正确的解析。恕我直言,正常形式&#34;功能分支你不应该在两个不同的提交中两次更改一行,每个提交应该呈现它所触及的行的最终版本,以帮助审阅者。但是,它可能发生在一个错误修正分支中,设想一个例子,提交A(将foo(bar());重命名为foo)并提交B(重命名fox可以触及行barbaz)。

如果您发现该脚本有用,请随时改进并重复使用它,也许有一天我们会在git中获得此类功能。我很高兴看到一个工具可以理解如何在交互式rebase引入合并冲突时解决它。

相关问题