我用:

git checkout -b testbranch

我做了20次提交。

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

git rebase -i HEAD~20

如果我不知道有多少次提交呢?有没有什么方法可以做到:

git rebase -i all on this branch

当前回答

为了完善一下Caveman的回答,使用git reset——soft <commit>。从文档中,这个命令:

根本不触及索引文件或工作树(但将头部重置为<commit>,就像所有模式一样)。这将使所有更改过的文件都变成“要提交的更改”,就像git状态所显示的那样。

换句话说,它将撤销到<commit>之前的所有提交。但是它不会改变工作目录。您最终会得到所有的更改,这些更改都是未分期和未提交的。就好像那些介入的提交从未发生过一样。

例子:

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

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

在我的手中,Caveman回答的第一部分(git rebase -i)并没有压缩提交。

其他回答

git checkout -b temp
git checkout yourbranch
git fetch
git reset --hard origin/master
git merge --squash temp
git commit -m "new message" 

最简单的方法。

这将创建一个新的分支,然后将你的分支重置为基础分支,然后在将临时分支合并回我们的分支之前,我们压缩更改并创建一个新的提交

在之前的回答中,我没有看到任何关于如何处理“凌乱的分支”和“自我冲突”的信息。例如,我经常在我的特性分支(称为特性)上有主提交,这导致了它们之间的冲突。我发现这是最难处理的问题之一。

如何挤压凌乱的树枝?使用临时分支!

我发现Felix Rieseberg的解决方案是最好的。以下是我对他的建议略短的抄写:

Create a local tmp branch of off master git checkout master && git pull && git checkout -b tmp Merge all feature changes into tmp (without any commits, only staged file changes). git merge --squash $feature Manually solve all remaining "real conflicts" (This is the only step you cannot have a script do for you) Commit. tmp is now master + 1 commit (containing all changes). git commit ... Checkout feature and git reset --hard tmp (feature's original contents are gone, and it is now basically tmp, but renamed) git checkout $feature && git reset --hard tmp Ignore and override origin/feature (then clean up) git push -f && git branch -D tmp

Felix指出,这将产生最干净的合并,没有任何来自master和feature之间混乱/复杂关系的奇怪的自我冲突:

您可能会遇到一些不可避免的合并冲突。请相信,这是尽可能少的冲突,因为您跳过了最初创建的许多中间提交。

How

你需要得到分支的合并基

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不同的分支,那么你可以用“$1”替换master来做到这一点

g-one-commit staging

另一种简单的方法是:在原始分支上进行合并-挤压。该命令不执行“压缩”提交。当你这样做时,你分支的所有提交消息将被收集。

$ 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: ...

签出您希望将所有提交压缩为一次提交的分支。我们说它叫feature_branch。

git checkout feature_branch

步骤1:

用你的本地主分支对你的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"