有没有一种方法可以非交互地压缩多个提交?


Answers:


146

确保您的工作树是干净的,然后

git reset --soft HEAD~3
git commit -m 'new commit message'

@wilhelmtell:太好了!现在,我可以构造一个git别名,例如“ mysquash 3'some message'”,将其缩减为一行吗?
菲利普(Phillip

5
如果只是行数:git reset --soft HEAD~3 && git commit -m "my message"
KingCrunch 2011年

7
@Phillip:您可以将shell函数嵌入git别名中。git config alias.mysquash '!f(){ git reset --soft HEAD~$1 && git commit ${2:+-m "$2"}; };f'git mysquash 3 'some message'可以使用,但我也对其进行了调整,因此git musquash 3将完全省略-m标志,以便git commit在这种情况下获得交互式UI。
莉莉·巴拉德

3
只是要说清楚:与南瓜不同。壁球还将合并提交消息。如果执行软重置,您将丢失所有提交信息。如果你想尝试壁球stackoverflow.com/a/27697274/974186
勒内链接

1
@sebnukem-那是我们尝试推动分支并且遥控器配置为拒绝强制推动的时候。
avmohan

30

我个人喜欢wilhelmtell的解决方案:

git reset --soft HEAD~3
git commit -m 'new commit message'

但是,我对别名进行了一些错误检查,以便您可以执行此操作:

git squash 3 'my commit message'

我建议设置实际运行脚本的别名,以使(a)编写脚本代码和(b)进行错误检查更加复杂。下面是执行壁球工作的脚本,然后在下面是用于设置git别名的脚本。

压榨脚本(squash.sh)

#!/bin/bash
#

#get number of commits to squash
squashCount=$1

#get the commit message
shift
commitMsg=$@

#regular expression to verify that squash number is an integer
regex='^[0-9]+$'

echo "---------------------------------"
echo "Will squash $squashCount commits"
echo "Commit message will be '$commitMsg'"

echo "...validating input"
if ! [[ $squashCount =~ $regex ]]
then
    echo "Squash count must be an integer."
elif [ -z "$commitMsg" ]
then
    echo "Invalid commit message.  Make sure string is not empty"
else
    echo "...input looks good"
    echo "...proceeding to squash"
    git reset --soft HEAD~$squashCount
    git commit -m "$commitMsg"
    echo "...done"
fi

echo
exit 0

然后要将squash.sh脚本连接到git别名,请制作另一个脚本来设置git别名,如下所示(create_aliases.commandcreate_aliases.sh):

#!/bin/sh
echo '-----------------------'
echo 'adding git aliases....'
echo '-----------------------'
echo
git config --global alias.squash "!bash -c 'bash <path to scripts directory>/squash.sh \$1 \$2' -"
#add your other git aliases setup here
#and here
#etc.
echo '------------------------------------'
echo 'here is your global gitconfig file:'
echo '------------------------------------'
more ~/.gitconfig
echo 
echo
echo '----------------'
echo 'end of script...'
echo '----------------'

4
您也可以将其放在$PATHnamed中git-squash.sh,它将自动别名为git squash。我没有更改您的答案,以防万一有理由使用create-aiases.sh我不知道的脚本。

我基本上使用create_aliases.command脚本,以便甚至我们的PM和设计人员也可以轻松进行设置。只需双击脚本就可以完成所有设置(特别是因为我在存储库中有安装脚本,并且知道了相对路径)。然后,他们甚至不需要重新启动终端。
n8tr 2014年

1
我尝试了此操作,它以壁球计数形式读取提交消息,但由于它不是整数,因此失败。
Minthos

1
解决的办法是追加- /squash.sh \ $ 1 \ $ 2'之后
Minthos

1
我喜欢解决方案的想法,但是解决方案中尚未考虑上述注释。单引号和双引号之间必须有一个负号。
物理

10

为了增加wilhelmtell的答案,我发现软重置为HEAD~2,然后修改以下内容的提交很方便HEAD~3

git reset --soft HEAD~2
git commit --all --amend --no-edit    

这会将所有提交合并到HEAD~3提交并使用其提交消息。确保从干净的工作树开始。


2
这是正确的答案,因为它压缩了一系列的提交,并使用了第一个提交的消息。它是非交互式的。
Landon Kuhn


3

使用以下命令将最后4次提交压缩为最后一次提交:

git squash 4

使用别名:

squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f"
sq = !git squash $1
sqpsf = !git squash $1 && git psf 

来自https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig


您未在此处指定正在使用的OS / shell。该解决方案可能不适用于人们使用的所有其他台式机。
Rick-777

是的,您应该为此使用linux / bash | zsh
brauliobo

2

这是一个可以挤压最后2次提交的班轮。在此示例中,将保留倒数第二次提交的消息。您可以根据需要更改消息。

git commit -am "$(git log -1 --skip=1 --pretty=%B | xargs && git reset --soft HEAD~2)"

如果您为此命令创建别名并改用别名,那么该命令将非常有用。


1

压榨自分支机构分支以来的所有内容:

git reset --soft $(git merge-base --fork-point master) \
  && git commit --verbose --reedit-message=HEAD --reset-author

--reedit-message=HEAD将使用不属于压榨最后一次提交的消息。这可能不是您想要的。为了获得要包含第一个提交的消息,或者(1)替换HEAD为您希望消息包含的提交的哈希值,或者(2)跳转到要包含的第一个提交的消息和git commit --amend --reedit-message=HEAD。这就是和谐的答案。
马兰(Maëlan)

-1

您可以与之接近

git rebase --on到HEAD〜4 HEAD〜master

假设您掌握线性历史记录。它不是壁球,因为它会丢弃中间提交。您需要修改新的HEAD才能修改提交消息。


谢谢格雷格;“丢弃”是指那些中间提交会被git gc清理吗?
菲利普(Phillip

@Phillip是的,中间的提交和旧的HEAD一样成为垃圾,因为它被重写为具有HEAD~4其父级。
格雷格·培根,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.