ChatGPT解决这个技术问题 Extra ChatGPT

合并(使用壁球)来自另一个分支的所有更改作为单个提交

git

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

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

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

是否有捷径可寻?

或者,从分支点开始压缩分支上所有提交的命令怎么样?


0
0 _

另一个选项是 git merge --squash <feature branch>,然后最后执行 git commit

来自Git merge

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


很酷的功能!我喜欢吉特。虽然我现在肯定会在将来使用它,但我仍然建议您了解 rebase -i 的方法。这是一项很好的技能,以防万一你真的想让它们不仅仅是一次提交。
提醒一句:这可行,但默认提交消息包括来自正在合并的分支的日志。问题是它看起来类似于您通常看到的格式,其中显示的整个文本实际上并没有成为提交消息的一部分,但在这种情况下它确实如此。因此,如果您不想要所有这些,则需要从提交消息中手动删除所有这些。我应该在使用它之前测试一下...
那,并且,被警告分支不会被视为合并。 stackoverflow.com/questions/19308790/…
恕我直言,这应该被称为 rebase --squash
所以(因为它并没有真正合并功能分支)如果您要在提交后删除功能分支,这将是合适的。那是对的吗? (我不是 git 专家)
B
Brad Robinson

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

git checkout master
git merge --squash WIP

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

git add .
git commit -m "Merged WIP"

git add . 做什么?
@MichaelPotter 它添加了所有文件和更改
git add . 在当前目录中添加所有未忽略的文件,我会小心以这种方式拾取意外文件。
作为 git add . 的替代,您可以使用 git add -u 仅添加已添加到树中的文件。
建议一个“git add .” be also done 令人困惑。当我执行“git merge --squash WIP”时,它已经在索引中有压缩的变化。所需要的只是提交它们。做一个“git add”。将添加碰巧在工作目录中但不属于功能分支的更改。问题是如何将功能分支中的更改作为一个提交提交。
f
fseto

在您的功能分支上尝试 git rebase -i master。然后,您可以将除一个“pick”之外的所有内容更改为“squash”以组合提交。请参阅squashing commits with rebase

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


是的,这行得通,但我不想要交互式 rebase 的麻烦。自从分支变平以来,我只想要一切。
+1 这使得历史清晰。将提交识别和管理为单独的补丁、卡片、故事等要容易得多。
r
raratiru

使用 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 和使用交互模式要好得多。易于记忆且易于使用。
A
Akbar Pulatov

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


这个想法是保留 history linear。但是,如果一个合并应该在图中可见,则可以用 one commit only 显示它,以避免在开发过程中产生的所有微提交的混乱。但是,如果图表中需要所有提交,则 merge 本身就可以解决问题。
S
Stephen Crosby

我已经创建了自己的 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 中进行一些额外的调整。
+1 这很优雅。对于这个想法的类似实现,它增加了一些功能,钟声和口哨,见github.com/arielf/clean-push
A
Arjun Mullick

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

对于较少的提交合并。

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

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


G
Gurjinder Singh

您有一个主分支和功能分支。您在功能分支上有很多提交。您不希望功能分支的所有提交都出现在 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 找到


N
NamshubWriter

您可以使用“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 Conceptuallyrebase 页面以获得良好的概述


这对我不起作用。我刚刚创建了一个带有 WIP 分支的简单测试存储库,并尝试了上述方法并遇到了合并冲突(即使我没有对 master 进行任何更改)。
如果功能是从 main (git checkout -b feature main) 创建的,并且您最近从 main 进行了合并,则不应从 rebase 中获得冲突
好的,再试一次。这次没有发生冲突,但历史没有被压扁。
再看一下 git-merge 文档,你是对的,一些提交将保留。如果您之前已经完成了从“main”到“feature”的合并,那么 rebase 将删除其中的一些,但不是全部。
请记住,如果之前发布了功能分支,那么变基可能会非常危险。有关 this SO question 的更多信息。