Git:如何压缩分支上的所有提交

我从master创建新的分支:

git checkout -b testbranch

我做了20个承诺。

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

git rebase -i HEAD~20

如果我不知道有多少次提交怎么办?有没有办法做到以下几点:

git rebase -i all on this branch
627878 次浏览

你正在做的事情很容易出错。只需:

git rebase -i master

这将仅自动将分支的提交重新定位到当前最新的主服务器上。

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

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

这并不完美,因为它意味着你知道“你的分支”来自哪个分支。
注意:发现原始分支不是使用Git轻松/可能视觉方式往往是最简单的,作为这里看到)。

注意:git branch --show-current随着Git 2.22(Q2 2019)引入


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


Karlotcha Hoa的评论中添加:

对于重置,你可以做

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

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


斯霍夫的评论中添加:

由于我的默认分支名为main,我的搜索多次将我带到这里:
下一次就可以了

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

另一种简单的方法是:转到源分支并执行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问题和答案,我认为这是一个很好的单行代码来压扁分支上的所有提交:

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

这假设master是基分支。

假设您从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计算提交的次数,因为您从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,则无需再执行此操作,因为它在合并分支时具有压扁选项Gitlab压缩选项

签出您想将所有提交压缩到一个提交中的分支。假设它被称为feature_branch

git checkout feature_branch

步骤1:

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

git reset --soft main

步骤2:

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

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

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

  1. 安装源代码树(它是免费的)

  2. 检查你的提交看起来如何。很可能你有类似的东西 输入图片描述

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

在此处输入图片描述

  1. 您可以通过单击按钮来压扁前一个提交。在我们的例子中,我们必须单击2次。您也可以更改提交消息 输入图片描述

  2. 结果很棒,我们准备好了! 输入图片描述

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

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

git log>branch.log

现在branch.log将从一开始就有所有的提交ID…向下滚动并获取第一次提交(这在终端会很困难) 使用第一次提交

git复位

所有提交将被压缩

正如之前许多答案中提到的那样,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

所有这些git重置,硬的,软的,这里提到的其他一切都可能工作(它不适合我),如果你正确地执行步骤和某种精灵。
如果你是普通的Joe smo,试试这个:
如何使用git合并--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合并--squashmy_new_feature

你所有的更改现在都将在你的新分支上,随时测试它,然后只做你的1个单一的提交,推送,该分支的新PR-并等待第二天重复。 你喜欢编程吗?:)

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

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

基本上你需要调用git squash master,你就完成了

由于我对这里提出的解决方案有一些问题,我想分享一个非常简单的解决方案(无论如何都有效):

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

前面的合并cmd确保,在提交时,来自master的最近更改不会在你的头上(反转)!之后,只需提交更改并执行git push -f

如果您使用基于JetBrains的IDE,例如IntelliJ创意并在命令行上使用GUI预览:

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

就是这样。你未提交所有更改。现在如果你要做一个新的提交,它将被压扁

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

这有点像git合并壁球,但不完全相同。

如何

您需要获取分支的合并库

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

解决方案-1

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

git pull origin master

B.对主控进行软复位

git reset --soft master

C.提交您的更改

git commit -m “commit message"

D.做git推送

git push --force

解决方案-2

使用git rebase压缩提交

A.

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

B.您将获得一个交互式提示,您需要选择顶部提交并在要组合/壁球的前面插入壁球或s

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

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

干杯!

您可以使用子命令ie执行此操作

$ git rebase -i HEAD~$(git rev-list --count HEAD ^master)

这将首先计算提交,因为您从master发散,然后重新调整到该确切长度。

要稍微完善穴居人的回答,请使用git reset --soft <commit>。从留档开始,此命令:

根本不接触索引文件或工作树(但将头部重置为<提交>,就像所有模式一样)。这将使所有更改的文件“更改要提交”,正如git status所说。

换句话说,它撤消了直到<commit>的所有提交。但它不会更改工作目录。你最终会得到所有的更改,未暂存和未提交。就好像那些介入的提交从未发生过一样。

示例:

# on master
git checkout -b testbranch
# make many commits
git reset --soft master
git add .
git commit -m 'The only commit.'

此时,您仍在testbranch上,它只有一个提交。像往常一样合并到master中。

穴居人的回答(git rebase -i)的第一部分没有在我手中壁球提交。

我知道这个问题已经被回答过了,但是我去写了一个bash函数,允许你在一个命令中完成它。它首先创建一个备份分支,以防壁球由于某种原因失败。然后壁球和提交。

# Squashes every commit starting after the given head of the given branch.
# When the squash is done, it will prompt you to commit the squash.
# The head of the given parent branch must be a commit that actually exists
# in the current branch.
#
# This will create a backup of the current branch before it performs the squash.
# The name of the backup is the second argument to this function.
#
# Example: $ git-squash master my-current-branch-backup
git-squash() {
PARENT_BRANCH=$1
BACKUP_BRANCH=$2


CURRENT_BRANCH=$(git branch --show-current)


git branch $BACKUP_BRANCH
BACKUP_SUCCESS=$?


if [ $BACKUP_SUCCESS -eq 0 ]; then
git reset $(git merge-base $PARENT_BRANCH $CURRENT_BRANCH)
git add -A
git commit
echo "Squashed $CURRENT_BRANCH. Backup of original created at $BACKUP_BRANCH$"
else
echo "Could not create backup branch. Aborting squash"
fi
}

假设您在功能分支上:

  1. 在功能分支中找到第一个提交。如果您使用gitlab或github并从那里复制哈希,您可以直接在分支中查看它,或者您可以使用以下命令:

git log <source_branch>..<feature_branch> --pretty=format:%h

  1. 执行以下命令:
git reset --soft <base_commit_hash>


git commit --amend --no-edit

现在在这个阶段,在您的本地,您有1个提交,其中包括在所有先前提交中完成的更改。

查看它,你需要强制推送它。强制推送后,所有的更改将合并在一个提交中,你的分支将只有1次提交。

  1. 在功能分支强制推送
git push --force