【问题标题】:Git: How to squash all commits on branchGit:如何压缩分支上的所有提交
【发布时间】:2014-10-10 23:35:39
【问题描述】:

我从master 创建新分支:

git checkout -b testbranch

我做了 20 次提交。

现在我想压缩这 20 个提交。我这样做:

git rebase -i HEAD~20

如果我不知道提交了多少次怎么办?有没有办法做类似的事情:

git rebase -i all on this branch

【问题讨论】:

  • 你可以做git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2d,它将做一个交互式rebase,其中commitnumber是最后一个保持不变的提交
  • @denns 使用这个方法和分支中的最后一次提交,你正在变基 from 非常棒。非常感谢!

标签: git version-control


【解决方案1】:

您正在做的事情很容易出错。做吧:

git rebase -i master

这将自动仅将您分支的提交重新定位到当前最新的 master 上。

【讨论】:

  • 同意这是您的最佳解决方案。但请关注link,因为它更好地解释了您需要做什么。
  • 您可以将分支合并到 master 并执行 git reset 到 origin/master 以取消暂存所有提交,而不是压缩提交。这将使您可以使用 commit -am "the whole thing!" 提交现有的未暂存代码
  • @nurettin 我认为reset origin/master 方法非常糟糕,因为它与直接在 master 上提交相同 - 没有“合并分支”历史记录,没有拉取请求选项。 @WaZaA 的回答更符合我认为的正常 git 工作流程
  • 其实我认为git merge --squash feature-branch 做同样的事情!有一个 GitHub 合并拉取请求壁球选项,认为这就是我要走的路线
  • @nurettin 您是否注意到在您自己的存储库上执行 Squash 和 Merge 之后,即使在合并之后分支仍然显示 7 commits ahead of master
【解决方案2】:

另一种压缩所有提交的方法是将索引重置为 master:

git checkout yourBranch
git reset $(git merge-base master $(git branch --show-current))
git add -A
git commit -m "one commit on yourBranch"

这并不完美,因为它意味着您知道“yourBranch”来自哪个分支。
注意:发现origin分支不是easy/possible with Gitvisual way is often the easiest,如seen here)。

注意:git branch --show-current 一直是 introduced with Git 2.22 (Q1 20219)


编辑:您需要使用git push --force


Karlotcha Hoa 添加in the comments

对于重置,你可以这样做

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[That] 自动使用您当前所在的分支。
如果您使用它,您也可以使用别名,因为该命令不依赖于分支名称

【讨论】:

  • 最好结帐以提交YourBranch 当前所在的位置。当您执行 reset 时,这将保持 YourBranch 不变
  • @Abdurrahim 或者打开一个 git bash,你可以复制粘贴这些命令!
  • 对于重置,您可以通过git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 自动使用您当前所在的分支。如果你使用它,你也可以使用别名,因为该命令不依赖于分支名称。
  • @Druska 对于 simlpe 分支案例,不,它应该可以正常工作。
  • @Shimmy 是的,只要您在重置后强制推送:git push --force(如果您有几个人在该分支上工作,请警告您的同事)
【解决方案3】:

另一种简单的方法是:转到源分支并执行merge --squash。此命令不执行“压扁”提交。当你这样做时,你的分支的所有提交消息都会被收集。

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...

【讨论】:

  • 是的。我在 stackoverflow.com/a/2427520/6309 中提到了 merge --squash 和 rebase -i 之间的区别
  • 如果您不想挤入父分支,这可行,只需创建并切换到基于父分支的新分支,然后将 squash 合并到该分支中。
  • 干杯伙伴,很棒的小费!
  • 不错!我首先从“master”创建一个“temp”分支,将“yourBranch”压缩到其中,然后将“temp”合并到“master”中。
【解决方案4】:

根据阅读有关压缩的几个 Stackoverflow 问题和答案,我认为这是压缩分支上所有提交的好方法:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

这是假设 master 是基础分支。

【讨论】:

  • 非常感谢,公司有很多限制,不能用编辑器重新设置通常的方法,因为没有大声保存。也无法在 git 中使用 squash 和合并功能,因为此分支转到 Lead dev 进行合并,他不喜欢它。这 1 班轮工作并节省了头痛。很棒的工作。
【解决方案5】:

假设你是从 master 分支的,你不需要一直在重置步骤中输入yourBranch

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

说明

  • git rev-list --count HEAD ^master 计算自从您从主 f.ex 创建功能分支以来的提交。 20.
  • git reset --soft HEAD~20 将对最后 20 次提交进行软重置。这会将您的更改保留在文件中,但会删除提交。

用法

在我的 .bash_profile 中,我为 gisquash 添加了一个别名,以便使用一个命令完成此操作:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

重置并提交后,您需要执行git push --force

提示

如果您使用的是 Gitlab >= 11.0,则不再需要这样做,因为它在合并分支时具有 squashing option

【讨论】:

    【解决方案6】:

    签出您想要将所有提交压缩为一个提交的分支。假设它叫feature_branch

    git checkout feature_branch
    

    第 1 步:

    使用本地 main 分支对 origin/feature_branch 进行软重置(根据您的需要,您也可以使用 origin/main 进行重置)。这将重置 feature_branch 中的所有额外提交,但不会在本地更改任何文件更改。

    git reset --soft main
    

    第 2 步:

    将 git repo 目录中的所有更改添加到将要创建的新提交中。并通过消息提交相同的内容。

    # Add files for the commit.
    git add ...
    git commit -m "commit message goes here"
    

    【讨论】:

    • 这对我来说是最可靠的解决方案 - 不会导致任何变基错误或合并冲突。
    • 警告:git add -A 将本地文件夹中的所有内容添加到分支中。
    • 喜欢这个解决方案!这正是我想要的!
    • 菜鸟的最佳解决方案 - 非破坏性且唯一的糟糕时刻可能会检查太多,例如应用程序机密等,如果您有正确的 gitignore 文件,这无关紧要
    • @BhimashankarMantur 如果您使用“--force”推送到现有分支,您可以使其工作 - 因为这个“git reset --soft”正在重写历史。但是,当然,您应该仅将“--force”推送到仅由您使用的分支 - 而不是共享的分支 - 除非您通知所有使用此类分支的人您的强制推送(例如,他们可以正确检索这些更改使用:“git pull --rebase origin my-branch-name”)
    【解决方案7】:

    喜欢点击的人的解决方案:

    1. 安装sourcetree(免费)

    2. 检查提交的外观。很可能你有类似的东西

    3. 右键单击 parent 提交。在我们的例子中,它是 master 分支。

    1. 您可以通过单击按钮来压缩前一个提交。在我们的例子中,我们必须点击 2 次。您还可以更改提交消息

    2. 结果非常好,我们准备好推动!

    旁注:如果您将部分提交推送到远程,则必须在 squash 后使用强制推送

    【讨论】:

    • 谢谢!
    • 我❤️点击。谢谢,马辛!
    【解决方案8】:

    另一种解决方案是将所有提交日志保存到文件中

    git 日志 > 分支.log

    现在 branch.log 将拥有自开始以来的所有提交 ID。向下滚动并进行第一次提交(这在终端中会很困难) 使用第一次提交

    git 重置 --soft

    所有提交都将被压缩

    【讨论】:

      【解决方案9】:

      正如之前许多答案中提到的,Git 重置是迄今为止实现您想要的最好和最简单的方法。我在以下工作流程中使用它:

      (在开发分支上)

      git fetch
      git merge origin/master  #so development branch has all current changes from master
      git reset origin/master  #will show all changes from development branch to master as unstaged
      git gui # do a final review, stage all changes you really want
      git commit # all changes in a single commit
      git branch -f master #update local master branch
      git push origin master #push it
      

      【讨论】:

        【解决方案10】:

        如果你正确地执行这些步骤并且是某种精灵,那么所有这些 git reset、hard、soft 以及这里提到的所有其他内容都可能正常工作(对我来说不是)。
        如果你是普通的 Joe smo,试试这个:
        How to use git merge --squash?


        救了我的命,我会去壁球,自从我发现它以来已经使用了 4 次。简单,干净,基本上 1 comamnd。 简而言之:


        如果您在一个分支上,让我们将其称为“my_new_feature”关闭开发,并且您的拉取请求有 35 个提交(或者很多),并且您希望它是 1。

        A. 确保您的分支是最新的,继续开发,获取最新并合并并解决与“my_new_feature”的任何冲突
        (无论如何,这一步你应该尽快采取)

        B. 获取最新的开发并分支到一个新的分支调用它 “my_new_feature_squashed”

        C. 魔法就在这里。
        您想将您的工作从“my_new_feature”转移到“my_new_feature_squashed”
        所以就这样做(在我们创建的新分支上,我们开发):
        git merge --squash my_new_feature

        您的所有更改现在都将在您的新分支上,随时对其进行测试,然后只需执行您的 1 次提交、推送、该分支的新 PR - 并等待第二天重复。
        你不喜欢编码吗? :)

        【讨论】:

          【解决方案11】:

          您可以使用我专门为此任务创建的工具:

          https://github.com/sheerun/git-squash

          基本上你需要打电话给git squash master然后你就完成了

          【讨论】:

            【解决方案12】:

            由于我在这里提出的解决方案遇到了一些问题,所以我想分享一个非常简单的解决方案(无论如何它确实有效):

            git merge origin/master && git reset --soft origin/master
            

            前面的合并 cmd 确保在提交时不会发生来自 master 的最新更改(倒置)!之后,只需提交更改并执行git push -f

            【讨论】:

            • 这种方法很有意义! Merge + reset = diff 然后 commit + push -f 更改历史记录。喜欢它
            • 这个真的很简单明了。找到这个做得很好!这帮助了我,而无需像其他答案那样创建额外的提交或步骤。
            • 我应该从哪个分支拨打这个电话?主分支还是功能分支?
            • 取决于你想要压缩提交的位置(通常在功能分支上)
            【解决方案13】:

            如果您使用基于 JetBrains 的 IDE,例如 IntelliJ Idea,并通过命令行使用 GUI:

            1. 转到版本控制窗口(Alt + 9/Command + 9)-“日志”选项卡。
            2. 在树中选择您创建分支的点
            3. 右键单击它 -> 将当前分支重置到此处 -> Pick Soft (!!!)(重要的是不要丢失您的更改)
            4. 按下对话框窗口底部的重置按钮。

            就是这样。您取消提交所有更改。现在,如果您要进行新的提交,它将被压扁

            【讨论】:

            • 如果您使用 Android Studio 的最佳答案,请 PS 右键单击​​并重置的分支是您的本地分支,同样当再次重新提交时,请选中提交按钮旁边的“修改提交”复选框,以确保您不'没有多个提交。
            • 请注明:git push --force
            • 发表上述评论后,我自己忘记了最重要的一步
            【解决方案14】:

            如果您对涉及另一个分支的答案感到满意,请尝试 git checkout --orphan <new_branch> 它允许我将前一个分支中的所有文件作为一个提交简单地提交。

            这有点像 git merge squash,但不完全相同。

            【讨论】:

              【解决方案15】:

              如何

              你需要得到你的分支的合并基础

              git merge-base master your-branch
              # 566f8438e0cd0e331ceb49a9cb0920143dfb065c
              

              然后你可以变基到它

              git rebase -i 566f8438e0cd0e331ceb49a9cb0920143dfb065c
              # then squash/pick/do commit messages
              

              或者只是进行软重置并提交所有内容

              git reset --soft 566f8438e0cd0e331ceb49a9cb0920143dfb065c
              git add .
              git commit -m "The only commit"
              

              自动化

              如果您经常这样做,您可以通过将它们放入您的 .bashrc 使用来自动化它。

              g-rebase-branch() {
                git branch --show-current | xargs git merge-base master | xargs git rebase -i
              }
              
              g-one-commit() {
                local last_commit_message=`git show -s --format=%s`
                git branch --show-current | xargs git merge-base master | xargs git reset --soft
                git add -A
                git commit -m "$last_commit_message"
                git commit --amend
              }
              

              然后直接在终端中执行这些操作。

              g-one-commit
              

              但如果您要合并到与 master 不同的分支,则可以将 master 替换为 "$1" 来执行此操作

              g-one-commit staging
              

              【讨论】:

                【解决方案16】:

                解决方案 - 1

                A.将 master 拉入您的功能分支(确保更新您的 Master)

                git pull origin master  
                

                B.对 master 进行软重置

                git reset --soft master
                

                C.提交您的更改

                git commit -m “commit message"
                

                D.做 git 推送

                git push --force  
                

                解决方案 - 2

                使用 git rebase 压缩提交

                答。

                $git rebase -i HEAD~3  (HEAD~<no. of commits you want to squash>)
                

                B. 您将获得一个交互式提示,您需要在其中选择顶部提交并在要合并/压缩的那些之前插入 squash 或 s

                注意:确保在插入模式下进行更改并保存文件; (VI编辑器中的wq)

                C. 现在您将看到另一个交互式提示,您需要将# 放在您不想要的提交消息的前面,或者添加您自己的消息。再次保存文件,您的提交将成功变基。

                干杯!

                【讨论】:

                • 当交互式变基过于残酷时,解决方案 #1 对我有用 - 例如一个非常古老的分支,上面有 122 个提交。交互式 rebase 很讨厌,在非常旧的文件上逐个提交,冲突多于没有。我只想压缩所有更改,重新设置基准,然后手动查看更改以查看哪些值得保留、哪些需要丢弃以及哪些需要更新。谢谢!
                猜你喜欢
                • 2019-08-14
                • 1970-01-01
                • 2021-03-17
                • 2015-03-08
                • 2010-12-12
                • 2016-07-16
                • 1970-01-01
                • 2020-10-24
                相关资源
                最近更新 更多