在 Git 中,有没有办法将所有更改从一个分支合并到另一个分支,但同时压缩到单个提交?
我经常在单独的分支中开发新功能,并且会定期提交/推送——主要用于备份或将我正在处理的内容转移到另一台机器上。大多数提交都说“Feature xxx WIP”或多余的东西。
一旦该工作完成并且我想将 WIP 分支合并回 master,我想丢弃所有这些中间提交,并且只有一个干净的提交。
是否有捷径可寻?
或者,从分支点开始压缩分支上所有提交的命令怎么样?
另一个选项是 git merge --squash <feature branch>
,然后最后执行 git commit
。
--squash --no-squash 生成工作树和索引状态,就好像发生了真正的合并(合并信息除外),但实际上不进行提交或移动 HEAD,也不记录 $GIT_DIR/MERGE_HEAD 导致下一个 git commit 命令创建一个合并提交。这允许您在当前分支之上创建一个提交,其效果与合并另一个分支相同(或者在章鱼的情况下更多)。
找到了!合并命令有一个 --squash
选项
git checkout master
git merge --squash WIP
此时,所有内容都已合并,可能有冲突,但未提交。所以我现在可以:
git add .
git commit -m "Merged WIP"
git add .
做什么?
git add .
在当前目录中添加所有未忽略的文件,我会小心以这种方式拾取意外文件。
git add .
的替代,您可以使用 git add -u
仅添加已添加到树中的文件。
在您的功能分支上尝试 git rebase -i master
。然后,您可以将除一个“pick”之外的所有内容更改为“squash”以组合提交。请参阅squashing commits with rebase
最后,您可以从 master 分支进行合并。
使用 accepted answer 建议的 git merge --squash <feature branch>
可以解决问题,但它不会将合并的分支显示为实际合并。
因此,更好的解决方案是:
从最新的 master 创建一个新分支,提交到特性分支启动的 master 分支。
使用 git merge --squash 将
将新创建的分支合并到 master 中。这样,功能分支将只包含一个提交,并且合并将在一个简短而整洁的插图中表示。
This wiki 详细解释了该过程。
在以下示例中,左侧屏幕截图是 qgit
的结果,右侧屏幕截图是以下结果:
git log --graph --decorate --pretty=oneline --abbrev-commit
两个屏幕截图显示了同一存储库中相同范围的提交。尽管如此,由于--squash
,正确的更紧凑。
随着时间的推移,主分支偏离了 db。
当 db 功能准备就绪时,一个名为 tag 的新分支在 db 具有其根的 master 的同一提交中创建。
从标记执行 git merge --squash db ,然后在一次提交中暂存和提交所有更改。
从 master 开始,标签被合并:git merge tag。
分支搜索无关紧要,不会以任何方式合并。
https://i.stack.imgur.com/7QK7i.jpg
git rebase -i master
和使用交互模式要好得多。易于记忆且易于使用。
2020 年更新
使用 --squash
标志,它看起来像两个没有关系的平行分支:
https://i.stack.imgur.com/I2Bhx.png
排序与日期相关的提交如下所示:
https://i.stack.imgur.com/g9F0X.png
就个人而言,我不喜欢 --squash 选项,试试这个技巧,也许它适合你的需要,我将它用于小型项目:
git init git checkout -b dev 在 dev 中的几个提交在你在 dev 中做了一些很棒的提交之后(但还没有合并到 master 中),如果你不希望所有提交都复制到 master 分支,那么故意在 master 中更改一些内容并(添加README 文件中的一些空行并在 master 中提交), git merge dev 它导致合并冲突(README 中的空行),解决它,提交你想要的新消息,你就完成了。这是它的视觉表示。
有意合并冲突的空提交,将其命名为您喜欢的任何名称
https://i.stack.imgur.com/pgABg.png
merge
本身就可以解决问题。
我已经创建了自己的 git 别名来做到这一点。我叫它git freebase
!它将获取您现有的混乱、不可重新定义的功能分支并重新创建它,以便它成为一个具有相同名称的新分支,其提交被压缩为一个提交并重新定位到您指定的分支(默认为 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"
通过运行从您的功能分支使用它:git freebase <new-base>
我只测试了几次,所以先阅读它并确保你想运行它。作为一项安全措施,它确实会打印起始 sha1,因此如果出现任何问题,您应该能够恢复旧分支。
我将在 github 上的 dotfiles 存储库中对其进行维护:https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig
grep
,因此需要在 Windows 中进行一些额外的调整。
git merge --squash <feature branch>
是一个不错的选择。“git commit”告诉您所有功能分支提交消息,您可以选择保留它。
对于较少的提交合并。
git merge do x 次 --git reset HEAD^ --soft 然后 git commit 。
被风险删除的文件可能会回来。
您有一个主分支和功能分支。您在功能分支上有很多提交。您不希望功能分支的所有提交都出现在 master 的提交历史记录中。按着这些次序
从最新的主代码创建一个新分支,您就在该分支中
git checkout -b latest_MCode
现在将您的功能分支合并到 latest_Mcode 分支
git merge --squash 功能
在没有 -m 参数的情况下提交
git commit # 没有 -m
编辑器应该是一个包含所有提交日志的弹出窗口,以及从功能分支更改的文件。您可以在此处查看所有功能分支提交。如果你愿意,你可以删除所有内容,只写一行你想在合并到 master 后显示的提交消息。按 i 然后写你的信息然后按 Esc->:wq->Enter 保存并退出编辑器。 4. 将新创建的分支合并到 master
git checkout master
git merge latest_Mcode
git push
你完成了!原始答案可在 GithubLink 找到
您可以使用“rebase”命令执行此操作。让我们称分支为“main”和“feature”:
git checkout feature
git rebase main
rebase 命令将重播“feature”上的所有提交,作为一个父级等于“main”的提交。
如果“main”在“feature”创建后(或最近一次合并)发生了变化,您可能希望在 git rebase main
之前运行 git merge main
。这样,您仍然拥有完整的历史记录,以防发生合并冲突。
在 rebase 之后,您可以将您的分支合并到 main,这应该会导致快进合并:
git checkout main
git merge feature
请参阅 Understanding Git Conceptually 的 rebase 页面以获得良好的概述
不定期副业成功案例分享
rebase --squash