将来自另一个分支的所有更改合并为单个提交

Bra*_*son 439 git

在Git中,有没有办法将所有更改从一个分支合并到另一个分支,但是同时压缩到一个提交?

我经常在一个单独的分支中处理一个新功能,并且会定期提交/推送 - 主要用于备份或将我正在处理的内容转移到另一台机器上.大多数提交说"功能xxx WIP"或多余的东西.

一旦完成该工作并且我想将WIP分支合并回master,我想丢弃所有这些中间提交,并且只需要一个干净的提交.

是否有捷径可寻?

或者,一个命令如何压缩分支上的所有提交,因为它是分支的点?

fse*_*eto 551

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

来自Git合并

--squash

--no-squash

生成工作树和索引状态,就好像发生了真正的合并(合并信息除外),但实际上没有提交或移动HEAD,也没有记录 $GIT_DIR/MERGE_HEAD导致下一个 git commit命令创建合并提交.这允许您在当前分支之上创建单个提交,其效果与合并另一个分支(或章鱼的情况下更多)相同.

  • 那个,并且,被警告说该分支不会被视为合并.http://stackoverflow.com/questions/19308790/git-branch-merged-no-merged-and-squash-option (17认同)
  • 需要注意的是:这是有效的,但默认提交消息包括来自正在合并的分支的日志.问题是它看起来类似于您通常看到的格式,其中显示的整个文本实际上不会成为提交消息的一部分,但在这种情况下确实如此.因此,如果您不想要所有这些,则需要从提交消息中手动删除所有内容.我应该在使用它之前测试过它... (4认同)
  • 很酷的功能!我喜欢吉特。虽然我将来肯定会使用它,但我仍然建议您了解 rebase -i 的方法。这是一项很好的技能,以防万一您确实想让它们不仅仅是一次提交。 (2认同)
  • 恕我直言,这应该被称为`rebase --squash` (2认同)

Bra*_*son 203

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

git checkout master
git merge --squash WIP
Run Code Online (Sandbox Code Playgroud)

此时所有内容都已合并,可能存在冲突,但未提交.所以我现在可以:

git add .
git commit -m "Merged WIP"
Run Code Online (Sandbox Code Playgroud)

  • 建议"git add".也做得很混乱.当我执行"git merge --squash WIP"时,它已经在索引中进行了压缩变更.所需要的只是提交它们.做一个"git add".将添加恰好位于工作目录中的更改,但这些更改不属于功能分支.问题是如何将功能分支中的更改作为一个提交提交. (17认同)
  • 作为`git add .`的替代,您可以使用`git add -u`来仅添加已添加到树中的文件. (7认同)
  • git add是做什么的? (2认同)
  • git add将在当前目录中添加所有不可忽略的文件,我会警惕以这种方式拾取不需要的文件。 (2认同)

fse*_*eto 25

试试git rebase -i master你的功能分支.然后,你可以将除了一个'pick'之外的所有内容更改为'squash'来组合提交.请参阅使用rebase压缩提交

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

  • 是的,但是我不希望交互式rebase的麻烦.自从分支扁平化以来,我只想要一切. (7认同)
  • +1这使得历史清晰.通过单独的补丁,卡片,故事等来识别和管理提交要容易得多. (2认同)

rar*_*iru 12

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

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

  • 创建一个新的分支 最新大师, 在功能分支启动的主分支中提交。
  • 合并<feature branch>到上面使用git merge --squash
  • 将新创建的分支合并到 master 中。这样,功能分支将只包含一个提交,合并将在一个简短而整洁的插图中表示。

这个 wiki详细解释了这个过程。

在下面的例子中,左手截图是结果,qgit右手截图是结果:

git log --graph --decorate --pretty=oneline --abbrev-commit
Run Code Online (Sandbox Code Playgroud)

两个屏幕截图都显示了同一存储库中相同范围的提交。尽管如此,由于--squash.

  • 随着时间的推移,master分支偏离了db
  • db功能准备好了,一个叫新的分支tag在同一创建提交的masterdb有其根源。
  • tagagit merge --squash db执行,然后所有更改都在单个提交中暂存和提交。
  • master,tag合并:git merge tag
  • 分支search无关紧要,不会以任何方式合并。

在此处输入图片说明

  • 对我来说,这实际上比执行“git rebase -i master”和使用交互模式要好得多。易于记忆且易于使用。 (2认同)

Akb*_*tov 6

2020 更新

有了--squash标志,它看起来就像两个没有关系的平行分支:

在此处输入图片说明

排序与日期相关的提交看起来像:

在此处输入图片说明

就个人而言,我不喜欢 --squash 选项,试试这个技巧,也许它适合你的需求,我将它用于小型项目:

  1. 混帐初始化
  2. git checkout -b dev
  3. 开发中的几次提交
  4. 在 dev 中做了一些很棒的提交(但还没有合并到 master 中)之后,如果你不想将所有提交复制到 master 分支,那么故意在 master 和(在 README 文件中添加一些空行并在 master 中提交)中进行一些更改,
  5. git merge dev 它导致合并冲突(自述文件中的空行),解决它,提交你想要的新消息,你就完成了。这是它的视觉表示。

有意合并冲突的空提交,将其命名为您喜欢的任何名称

有意合并冲突的空提交

  • 这个想法是保持[历史线性](/sf/answers/3932595551/)。但是,如果合并应该在图中可见,则可以显示[仅一次提交](/sf/answers/4250025181/),以避免开发过程中产生的所有微提交的混乱。但是,如果图中需要所有提交,“merge”本身就可以实现这一点。 (2认同)

Ste*_*sby 5

我创建了自己的 git 别名来做到这一点。我正在呼唤它git freebase!它将采用您现有的混乱的、不可rebasable的功能分支并重新创建它,以便它成为一个具有相同名称的新分支,其提交被压缩为一个提交并重新基于您指定的分支(默认为master)。最后,它将允许您为新的“基于自由”的分支使用您喜欢的任何提交消息。

通过在 .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"
Run Code Online (Sandbox Code Playgroud)

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

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

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