在编写新代码时,我会进行许多小的提交以跟踪我的更改。然而,我的公司更喜欢将每个功能作为单个提交提交。因此,解决方案是将整个(本地)分支压缩为单个提交。
如何在不使用 git rebase --interactive
并更改所有提交的 pick
为 squash
的情况下将整个分支压缩?
在编写新代码时,我会进行许多小的提交以跟踪我的更改。然而,我的公司更喜欢将每个功能作为单个提交提交。因此,解决方案是将整个(本地)分支压缩为单个提交。
如何在不使用 git rebase --interactive
并更改所有提交的 pick
为 squash
的情况下将整个分支压缩?
这是一个完美的应用场景,可以使用 git reset --soft
命令。
假设您有一个提交历史记录
D Your latest patch
C Your second patch
B Your first patch
A Someone else's work
你当前没有暂存的更改,而且 git status
、git log
或 git show
命令告诉你现在所在的提交是 D。
接着,执行 git reset --soft B
命令将把提交 C
和 D
的累积更改暂存起来以备提交。然后,执行 git commit --amend
命令将这些更改“合并”到提交 B 中。
使用方法如下:
git reset --soft B
git commit --amend
第二个命令将打开您的编辑器并有机会编辑提交消息。 git add XXX
但没有跟进 git commit
),则这些暂存的更改也将合并到提交中。fatal: refusing to merge unrelated histories
。 - Chris Moschini获取最新的 origin/master
分支:
$ git fetch
通过将本地分支重置到 origin/master
来丢弃所有提交:
$ git reset --mixed origin/master
将之前分支状态下的所有更改合并到索引中:
$ git merge --squash HEAD@{1}
提交您的更改 - Git 将使用包含所有合并提交消息的提交消息预填充您的编辑器
alias squash="git fetch; git reset --mixed origin/master; git merge --squash HEAD@{1}"
git reset --mixed
而不是 --hard
?在我的情况中,混合重置保留了工作副本中获取的所有文件,但合并步骤失败了。 - Mariano Desanzegit merge --squash
。这将保留您的分支开发历史记录,这通常更容易排除故障,因为您会知道“我正在提交Z中更改特定功能”,并且查看该特定提交,您可以了解到您对多个文件所做的任何更改的所有上下文 - 查看单个提交,它是您开发路径压缩结果,使得记住“哦,是的,我还必须在另一个文件中更改这一点...”变得更加困难。此外,当您有整个路径可用时,您还可以使用git bisect
获得好处 - 在压缩情况下,它只能告诉您“这个巨大的提交在这里破坏了某些东西”。git merge --squash
的结果是在您“合并”的分支上的单个提交,其中包含来自您的分支的累积更改,但它不会影响您的原始分支。$ git reset --soft [hash]
$ git add -A
$ git commit -m 'EVERYTHING SQUASHED'
--soft
标志 (git reset --soft <commit>
),因为 Git 默认执行混合重置。 - jub0bs编辑你的 git 配置文件 ~/.gitconfig
并在别名部分添加以下内容:
[alias]
squash = "!f(){ CUR=`git rev-parse HEAD` && git reset --soft ${1} && git commit -m \"$(git log --format=%B ${1}..${CUR})\"; };f"
这个别名获取当前的 HEAD 提交哈希值,重置回到您指定的提交,并创建一个新的提交,保留所有提交信息。
用法:
git squash <refspec>
refspec可以是任何有效的提交引用,例如提交哈希值、分支名称、标签名称、HEAD^
、HEAD~3
我认为这不是这个问题的正确答案。
但是在向远程上游主分支发出拉取请求之前,我通常会使用以下命令压缩我的分支:
git rebase -i master
但是你仍然需要选择哪一个要挑选和压缩。
我喜欢的压缩方式是通过重新分组提交,而不需要变基,这样我之后只需变基即可。
# Squash current branch from its departure point in main branch. You must run
# this command when on your branch's last commit.
git-squash() {
# https://dev59.com/32Ml5IYBdhLWcg3wbGh1#48524405
local main_commit="$(git merge-base HEAD main)"
local last_branch_commit="$(git rev-parse HEAD)"
git reset --soft "$main_commit"
# Preserve commits
git commit -em "$(git log --reverse --format=%B ${main_commit}..${last_branch_commit})"
}
源代码(以及在dotfiles中的集成)。受troymass的另一个答案启发。
当然,现在你可以使用git rebase main
进行变基了。
注意:如果您是zsh用户,可以在此处将main
替换为git_main_branch
。这将选择主分支(main)或主干(master)。
[alias]
squash = "!f() { git reset --hard $1; git merge --squash HEAD@{1}; git commit; }; f"
这样你就可以这样调用它:
git squash master
或者从另一个分支(如dev
)合并:
git squash dev
git merge --squash
,这样就不需要事先将整个分支压缩成一个提交了。 - twalberggit merge --squash
无法正常工作,而这是非常常见的情况。 - user229044dev
分支上完成所有工作,然后在integration
分支上执行git --merge squash
,并将integration
用作拉取请求的源。 - twalberggit reset --soft
,然后再使用git commit
。 - Alexey