合并(压扁)来自另一个分支的所有更改作为一次提交


479

在Git中,是否有一种方法可以将所有更改从一个分支合并到另一个分支,但同时压缩到单个提交?

我经常在单独的分支中研究新功能,并且会定期提交/推送-主要用于备份或将我正在处理的内容转移到另一台计算机上。通常,那些提交会说“功能xxx WIP”或多余的内容。

工作完成后,我想将WIP分支合并回master,我想放弃所有这些中间的提交,只剩下一个干净的提交。

是否有捷径可寻?

或者,压缩一个分支后的所有提交的命令又如何呢?

Answers:


600

git merge --squash <feature branch>然后,另一个选择是最后做一个git commit

Git合并

--squash

--no-squash

产生工作树和索引状态,就好像发生真正的合并一样(合并信息除外),但实际上不进行提交或移动HEAD,也不记录 $GIT_DIR/MERGE_HEAD导致下一个 git commit命令创建合并提交。这使您可以在当前分支的顶部创建一个提交,其作用与合并另一个分支的作用相同(对于章鱼,则更多)。


1
很酷的功能!我喜欢git。虽然我现在肯定会在将来使用它,但我仍然建议您了解使用rebase -i的方法。这是一项很好的技能,以防万一您确实确实希望使它们不仅仅是一次提交。

4
提醒您:这行得通,但是默认的提交消息包括来自合并分支的日志。问题在于它看起来与您通常看到的格式类似,其中显示的整个文本实际上并未成为提交消息的一部分,但在这种情况下确实如此。因此,如果您不想要所有这些,则需要从提交消息中手动将其全部删除。我应该在使用它之前对其进行测试……
still_dreaming_1 2014年

23
请注意,该分支将不会被视为合并。stackoverflow.com/questions/19308790/…–
赖安

3
恕我直言,这应该被称为rebase --squash
Andy

因此(由于它实际上并未合并功能分支),如果您打算在提交后删除功能分支,则这将是适当的。那是对的吗?(我不是git专家)
安德鲁·斯宾塞

214

找到了!合并命令有一个--squash选项

git checkout master
git merge --squash WIP

此时,所有内容都已合并,可能会发生冲突,但尚未提交。所以我现在可以:

git add .
git commit -m "Merged WIP"

2
怎么git add .办?
迈克尔·波特

1
@MichaelPotter它添加了所有文件和更改
Daksh Shah

2
git add .会在当前目录中添加所有不可忽略的文件,因此请谨慎选择这种方式。
杰克·科布

7
作为替代方案,git add .您可以git add -u用来仅添加已经添加到树中的文件。
布兰登·奥格尔

19
提示“ git add”。也做得令人困惑。当我执行“ git merge --squash WIP”时,它已经在索引中具有压缩的更改。所有需要做的就是提交它们。进行“ git add”。将添加恰好在工作目录中但不属于功能分支的更改。问题是如何将功能分支中的更改作为一次提交提交。
约翰·潘科维奇

30

尝试git rebase -i master您的功能分支。然后,您可以将除一个“ pick”之外的所有内容都更改为“ squash”以合并提交。查看使用rebase压缩提交

最后,您可以从master分支进行合并。


8
是的,这行得通,但我不希望麻烦进行交互式基础调整。我只想要分支扁平化以来的一切。
布拉德·罗宾逊

2
+1这可以使历史记录整洁。这是一个更容易识别和管理人员犯个别修补程序,卡,故事等
瑞安

2

使用git merge --squash <feature branch>作为可接受的答案可以解决问题,但不会将合并的分支显示为实际合并的分支。

因此,更好的解决方案是:

  • 从最新的母版创建一个新分支
  • 合并<feature branch>到上面使用git merge --squash
  • 将新创建的分支合并到master

该Wiki详细解释了该过程。


0

我已经创建了自己的git别名来做到这一点。我在叫它git freebase!它将使用您现有的混乱,无法修复的功能分支并重新创建它,以使其成为具有相同名称的新分支,其提交被压缩为一次提交并重新基于您指定的分支(默认为master)。最后,它将允许您将喜欢的任何提交消息用于新的“基于Freefree”的分支。

通过在您的.gitconfig中放置以下别名来安装它:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

通过运行以下命令从功能分支中使用它: git freebase <new-base>

我只测试了几次,所以请先阅读并确保您要运行它。作为一点安全措施,它确实会打印起始sha1,因此,如果出现任何问题,您应该能够恢复旧分支。

我将在github上的dotfiles仓库中维护它:https : //github.com/stevecrozz/dotfiles/blob/master/.gitconfig



-1

git merge --squash <feature branch> 是一个不错的选择。“ git commit”告诉您所有功能分支提交消息,并选择保留它。

对于较少的提交合并。

git merge做x次--git reset HEAD ^ --soft然后git commit。

风险删除的文件可能会回来。


-5

您可以使用“ rebase”命令执行此操作。让我们将分支称为“ main”和“ feature”:

git checkout feature
git rebase main

rebase命令将重播“功能”上的所有提交,作为父级等于“主要”的一次提交。

如果自创建“功能”以来(或自最近的合并以来)“ main”已更改git merge maingit rebase main则可能要先运行。这样,如果发生合并冲突,您仍然拥有完整的历史记录。

重新设置基准后,可以将分支合并到main,这将导致快速合并:

git checkout main
git merge feature

底垫的页面了解Git的概念进行了很好的概述


这对我不起作用。我只是用WIP分支创建了一个简单的测试仓库,并尝试了上述操作并遇到了合并冲突(即使我没有对master进行任何更改)。
布拉德·罗宾逊

如果功能是从main创建的(git checkout -b feature main),并且您最近从main进行了合并,那么您应该不会从rebase中收到冲突
NamshubWriter 2010年

好,再试一次。这次没有冲突,但是历史没有被挤压。
布拉德·罗宾逊

再看一下git-merge文档,您是对的,有些提交会保留下来。如果您以前完成了从“主”到“功能”的合并,则重新设置基准将删除其中一些,但不是全部。
NamshubWriter 2010年

请记住,如果功能分支先前已发布,则重新部署可能非常危险。有关此问题的更多信息。
罗伯特·罗斯曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.