有没有办法以非交互方式压缩大量提交?

Posted

技术标签:

【中文标题】有没有办法以非交互方式压缩大量提交?【英文标题】:Is there a way to squash a number of commits non-interactively? 【发布时间】:2011-11-08 16:24:59 【问题描述】:

我正在尝试压缩一系列提交 - HEAD 到 HEAD~3。有没有一种快速的方法可以做到这一点,还是我需要使用 rebase --interactive?

【问题讨论】:

类似问题:***.com/questions/5189560/… 【参考方案1】:

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

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

【讨论】:

@wilhelmtell:太好了!现在我可以构建一个 git 别名,例如“mysquash 3 'some message'”,将其缩减为一行? 如果只是行数:git reset --soft HEAD~3 && git commit -m "my message" @Phillip:你可以在 git 别名中嵌入一个 shell 函数。 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。 只是为了明确一点:它与壁球不同。壁球也会合并提交消息。如果您进行软重置,您将丢失所有提交消息。如果你想壁球试试***.com/a/27697274/974186 @sebnukem - 那是我们尝试推送分支并且远程配置为拒绝强制推送的时候。【参考方案2】:

我个人喜欢wilhelmtell's解决方案:

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

但是,我创建了一个带有一些错误检查的别名,以便您可以这样做:

g.squash 3 'my commit message'

我建议设置实际运行脚本的别名,以便更容易 (a) 编写脚本并 (b) 进行更复杂的错误检查工作。下面是一个执行挤压工作的脚本。我把它放在我的 HOME 路径中的脚本文件夹中。

压缩脚本 (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 脚本连接到别名,我将以下内容添加到我的 .zprofile:

export PATH="$PATH:$HOME/scripts" # Add scripts folder to PATH
...
alias g.squash='function _gSquash() sh squash.sh $1 $2; ;_gSquash'
...

注意:您可以随意设置别名。我有很多我的 git 快捷方式 g.<myCommand>

【讨论】:

你也可以把它放在$PATH命名为git-squash.sh,它会自动别名为git squash。我没有更改您的答案,以防万一有理由使用我不知道的create-aiases.sh 脚本。 我基本上使用 create_aliases.command 脚本,这样即使我们的 PM 和设计师也可以轻松进行设置。只需双击脚本,它们就全部设置好了(特别是因为我在我们的 repo 中有设置脚本并且相对路径是已知的)。然后他们甚至不需要重新启动终端。 我试过这个,它把我的提交信息读成壁球计数,但因为它不是整数而失败。 解决方案是在 /squash.sh \$1 \$2' 之后附加 - 我喜欢解决方案的想法,但是解决方案中尚未考虑到上面的评论。单引号和双引号之间需要有一个减号。【参考方案3】:

要补充wilhelmtell的答案,我发现软重置为HEAD~2然后修改HEAD~3的提交很方便:

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

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

【讨论】:

这是正确的答案,因为它压缩了一系列导致 head 的提交,并且它使用了第一个提交的消息。它是非交互式的。 在这种情况下,我认为git commit中的--all参数是不必要的,因为修改后的文件在软重置后已经暂存。 Doc for git commit --all【参考方案4】:

我用过:

EDITOR="sed -i '2,/^$/s/^pick\b/s/'" git rebase -i <ref>

工作得很好。只是不要试图让提交日志的行以“pick”开头:)

【讨论】:

遗憾的是,这在 Windows 上对我不起作用。仍然获取交互式编辑器。 在 Mac 上都不适合我【参考方案5】:

使用以下命令压缩最后一次提交中的最后 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

【讨论】:

您没有指定这里使用的操作系统/shell。此解决方案可能不适用于人们使用的所有其他桌面。 是的,你应该使用 linux/bash|zsh 来做这个【参考方案6】:

这是一个用于压缩最后 2 次提交的单行。在此示例中,将保留倒数第二次提交的消息。您可以随意更改消息。

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

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

【讨论】:

【参考方案7】:

从 master 分叉后压缩所有内容:

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。这就是和谐的答案。【参考方案8】:

你可以很接近

git rebase --onto HEAD~4 HEAD~ master

这假设您是具有线性历史的大师。它不是一个壁球,因为它丢弃了中间提交。您需要修改新的 HEAD 以修改提交消息。

【讨论】:

谢谢格雷格; 'discards' 是否意味着这些中间提交需要被 git gc 清理? @Phillip 是的,中间提交和旧的 HEAD 一样成为垃圾,因为它被重写为以 HEAD~4 作为其父级。

以上是关于有没有办法以非交互方式压缩大量提交?的主要内容,如果未能解决你的问题,请参考以下文章

如何以非交互方式在 Git 中重新排序提交

以非交互方式执行 rgrep

如何以非阻塞方式压缩文件

如何以非交互方式为“psql”指定密码?

如何通过非交互方式压缩除最近提交之外的所有提交来减少臃肿的 Git 存储库的大小?

如何以非交互方式分析 Java 应用程序?