如何将所有git提交压缩成一个?

Ver*_*gen 427 git rebase git-rebase squash git-rewrite-history

你如何将整个存储库压缩到第一次提交?

我可以重新设置第一次提交,但这会让我有2次提交.有没有办法在第一个之前引用提交?

Jor*_*wis 621

在最新版本的git中,您可以使用git rebase --root -i.

对于除第一个之外的每个提交,请更改picksquash.

  • 请添加一个完整的,有效的命令示例来回答原始问题. (44认同)
  • 这个答案是*ok*,但是如果你交互式地重新定位超过20次提交,那么交互式rebase可能会太慢而且不实用.你可能很难尝试压制数百或数千次提交.我会使用软复位或混合复位到根提交,然后重新发送,在这种情况下. (37认同)
  • 我希望我在读完这个之前就像我接受的答案所说的那样: (27认同)
  • @Pred不要对所有提交使用`squash`.第一个需要是"挑选". (18认同)
  • 如果你有很多提交,很难手动将'pick'改为'squash'.在VIM命令行中使用_:%s/pick/squash/g_可以更快地完成此操作. (7认同)
  • 这可以找到,但我不得不强制推送。当心!`git Push -f` (5认同)
  • 没有先前的提交,我一直在"不能"压扁.或者我只是得到目录是脏的,或者已经有一个现有的rebase. (4认同)
  • 1.7.12 新增:https://github.com/git/git/blob/master/Documentation/RelNotes/1.7.12.txt (3认同)
  • @eilas 不需要“g”。您只想替换每行中单词“pick”的第一个实例。更好的是 `:%s/^pick/squash/`。 (3认同)
  • 对于nano用户,使用`ctrl+\`来触发搜索/替换。 (2认同)

rye*_*nus 291

更新

我做了一个别名git squash-all.
用法示例:git squash-all "a brand new start".

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"
Run Code Online (Sandbox Code Playgroud)

警告:记得提供评论,否则将使用默认提交消息"新的开始".

或者,您可以使用以下命令创建别名:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'
Run Code Online (Sandbox Code Playgroud)

一个班轮

git reset $(git commit-tree HEAD^{tree} -m "A new start")
Run Code Online (Sandbox Code Playgroud)

注意:这里A new start只是一个例子,随意使用您自己的语言.

TL; DR

无需压缩,用于git commit-tree创建孤立提交并使用它.

说明

  1. 通过创建一个提交 git commit-tree

    git commit-tree HEAD^{tree} -m "A new start"是什么:

    基于提供的树对象创建新的提交对象,并在stdout上发出新的提交对象ID.除非给出-m或-F选项,否则将从标准输入中读取日志消息.

    表达式HEAD^{tree}表示对应的树对象HEAD,即当前分支的尖端.请参见树对象提交对象.

  2. 将当前分支重置为新提交

    然后git reset只需将当前分支重置为新创建的提交对象.

这样,工作区中没有任何东西被触及,也不需要变形/壁球,这使得它非常快.所需时间与存储库大小或历史深度无关.

变化:项目模板的新回购

这对于使用另一个存储库作为模板/ archetype/seed/skeleton在新项目中创建"初始提交"很有用.例如:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")
Run Code Online (Sandbox Code Playgroud)

这样可以避免将模板仓库添加为远程(origin或其他),并将模板仓库的历史记录折叠到初始提交中.

  • 这里解释了git修订语法(HEAD ^ {tree})语法,以防其他人想知道:http://jk.gs/gitrevisions.html (6认同)
  • @aleclarson,这只重置本地存储库中的当前分支,使用`git push -f`进行传播. (4认同)
  • 你可以摆脱那个"警告"但只使用`$ {1?请输入消息}` (3认同)
  • 这会重置本地和远程存储库,还是仅重置其中之一? (2认同)
  • 我找到了这个答案,同时寻找一种从不涉及`git clone`的项目模板库启动新项目的方法.如果你将`--hard`添加到`git reset`并在`git commit-tree`中用`FETCH_HEAD`切换`HEAD`,你可以在获取模板repo后创建一个初始提交.我在最后一节中编辑了答案,展示了这一点. (2认同)

小智 158

如果您只想将所有提交压缩到根提交,那么同时

git rebase --interactive --root
Run Code Online (Sandbox Code Playgroud)

可以工作,对于大量提交(例如,数百次提交)来说是不切实际的,因为rebase操作可能会非常缓慢地运行以生成交互式rebase编辑器提交列表,以及运行rebase本身.

当您压缩大量提交时,这里有两个更快,更有效的解决方案:

替代解决方案#1:孤儿分支

您可以在当前分支的提示(即最近提交)处创建一个新的孤立分支.这个孤立分支形成了一个全新的独立提交历史树的初始根提交,这实际上相当于压缩所有提交:

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master
Run Code Online (Sandbox Code Playgroud)

文档:

替代解决方案#2:软复位

另一个有效的解决方案是简单地对根提交使用混合或软重置<root>:

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset
Run Code Online (Sandbox Code Playgroud)

文档:

  • 替代解决方案#1:孤儿分支 - 岩石! (18认同)
  • 替代解决方案#1 FTW.只是要补充一点,如果你想将你的更改推送到遥控器,请执行`git push origin master --force`. (7认同)
  • 不应该忘记`git push --force` (2认同)
  • 如果您要推送到开放的 Github 拉取请求,请不要在代码上执行孤立分支(即不要执行上面的替代解决方案 #1)!Github 将关闭您的 PR,因为[当前头不是存储的头 sha 的后代](https://github.com/isaacs/github/issues/361)。 (2认同)

Pat*_*otz 129

也许最简单的方法是使用工作副本的当前状态创建一个新的存储库.如果要保留所有可以先执行的提交消息git log > original.log,然后在新存储库中编辑初始提交消息:

rm -rf .git
git init
git add .
git commit
Run Code Online (Sandbox Code Playgroud)

要么

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
Run Code Online (Sandbox Code Playgroud)

  • 自从给出这个答案以来,Git已经发展了.不,有一种更简单,更好的方法:`git rebase -i --root`.请参阅:http://stackoverflow.com/a/9254257/109618 (124认同)
  • 但你用这种方法失去了分支 (59认同)
  • -1表示这种破坏性方法. (18认同)
  • 这可能适用于某些情况,但它本质上不是问题的答案.使用此配方,您也会丢失所有配置和所有其他分支. (5认同)
  • 也会破坏子模块.-1 (5认同)
  • 这样做您将丢失所有存储库信息。 (2认同)
  • 这是一个可怕的解决方案,不必要地具有破坏性。请不要使用它。 (2认同)

kus*_*sma 48

echo "message" | git commit-tree HEAD^{tree}
Run Code Online (Sandbox Code Playgroud)

这将使用HEAD树创建一个孤立提交,并在stdout上输出它的名称(SHA-1).然后在那里重置你的分支.

git reset SHA-1
Run Code Online (Sandbox Code Playgroud)

  • `git reset $(git commit-tree HEAD ^ {tree} -m"commit message")`会让它变得更容易. (25认同)
  • 这个! - 应该是一个答案.不完全确定这是作者的意图,但是我的(需要一个单一提交的原始回购,并且完成工作). (3认同)
  • 我自己不建议使用subshel​​l变量的原因是,它在Windows中的cmd.exe上不起作用。 (2认同)

Log*_*gan 38

以下是我最终如何做到这一点,以防它适用于其他人:

请记住,做这样的事情总是存在风险,在开始之前创建保存分支绝对不错.

从记录开始

git log --oneline
Run Code Online (Sandbox Code Playgroud)

滚动到第一次提交,复制SHA

git reset --soft <#sha#>
Run Code Online (Sandbox Code Playgroud)

替换<#sha#>w /从日志中复制的SHA

git status
Run Code Online (Sandbox Code Playgroud)

确保一切都是绿色的,否则运行 git add -A

git commit --amend
Run Code Online (Sandbox Code Playgroud)

修改当前第一次提交的所有当前更改

现在强行推动这个分支,它将覆盖那里的东西.


CB *_*ley 34

最简单的方法是使用'plumbing'命令update-ref删除当前分支.

您不能使用git branch -D因为它有一个安全阀来阻止您删除当前分支.

这会使您回到"初始提交"状态,您可以从新的初始提交开始.

git update-ref -d refs/heads/master
git commit -m "New initial commit"
Run Code Online (Sandbox Code Playgroud)


R. *_*des 31

我读了一些关于使用移植物的内容,但从未对它进

无论如何,你可以手动压缩最后2次提交,如下所示:

git reset HEAD~1
git add -A
git commit --amend
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是我正在寻找的答案,希望它是被接受的答案! (4认同)

Fre*_*abe 16

首先,使用将所有提交压缩为单个提交git rebase --interactive.现在你有两个提交壁纸.为此,请阅读任何内容


kyb*_*kyb 13

在一行6个字

git checkout --orphan new_root_branch  &&  git commit
Run Code Online (Sandbox Code Playgroud)

  • 简单的。这是[`git help checkout --orphan`](https://git-scm.com/docs/git-checkout#Documentation/git-checkout.txt---orphanltnewbranchgt) (2认同)

小智 9

为此,您可以将本地 git 存储库重置为第一个提交主题标签,以便在该提交之后的所有更改都将取消暂存,然后您可以使用 --amend 选项进行提交。

git reset your-first-commit-hashtag
git add .
git commit --amend
Run Code Online (Sandbox Code Playgroud)

然后根据需要编辑第一个提交 nam 并保存文件。

  • 这应该被接受的答案,因为这保留了其他分支 (2认同)

小智 9

假设您的分支中有 3 个提交,并且它已经被推送到远程分支。

例子:

git log -4
Run Code Online (Sandbox Code Playgroud)

将显示如下结果:

<your_third_commit_sha>
<your_second_commit_sha>
<your_first_commit_sha>
<master_branch_commit_sha - your branch created from master>
Run Code Online (Sandbox Code Playgroud)

您希望将最后 3 次提交压缩为一次提交并推送到远程分支。以下是步骤。

git reset --soft <master_branch_commit_sha>
Run Code Online (Sandbox Code Playgroud)

现在所有提交更改都已集成但未提交。验证方式:

git status
Run Code Online (Sandbox Code Playgroud)

通过消息提交所有更改:

git commit -m 'specify details'
Run Code Online (Sandbox Code Playgroud)

强制将单个提交推送到远程分支:

git push -f
Run Code Online (Sandbox Code Playgroud)


Dav*_*vid 7

创建一个备份

git branch backup
Run Code Online (Sandbox Code Playgroud)

重置为指定的提交

git reset --soft <#root>
Run Code Online (Sandbox Code Playgroud)

然后将所有文件添加到暂存

git add .
Run Code Online (Sandbox Code Playgroud)

提交而不更新消息

git commit --amend --no-edit
Run Code Online (Sandbox Code Playgroud)

推送新的分支并压缩回购

git push -f
Run Code Online (Sandbox Code Playgroud)


dim*_*mus 6

使用移植物压扁

添加一个文件.git/info/grafts,把你想成为根的提交哈希放在那里

git log 现在将从那个提交开始

让它“真正”运行 git filter-branch


Ken*_*sen 5

我通常这样做:

  • 确保所有内容都已提交,并记下最新的提交 ID,以防出现问题,或者创建一个单独的分支作为备份

  • 运行git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`以将头重置为第一次提交,但保持索引不变。自第一次提交以来的所有更改现在都将显示为可以提交。

  • 运行git commit --amend -m "initial commit"将您的提交修改为第一个提交并更改提交消息,或者如果您想保留现有的提交消息,您可以运行git commit --amend --no-edit

  • 运行git push -f以强制推动您的更改


Vla*_*hin 5

对我来说,它是这样工作的:我总共有 4 次提交,并使用了交互式变基:

git rebase -i HEAD~3
Run Code Online (Sandbox Code Playgroud)

第一个提交仍然存在,我进行了 3 个最新提交。

如果您卡在接下来出现的编辑器中,您会看到如下内容:

pick fda59df commit 1
pick x536897 commit 2
pick c01a668 commit 3
Run Code Online (Sandbox Code Playgroud)

你必须首先提交并把其他人压在上面。你应该拥有的是:

pick fda59df commit 1
squash x536897 commit 2
squash c01a668 commit 3
Run Code Online (Sandbox Code Playgroud)

为此,请使用 INSERT 键更改“插入”和“编辑”模式。

要保存并退出编辑器,请使用:wq. 如果您的光标位于这些提交行之间或其他位置,请按 ESC 并重试。

结果我有两次提交:第一个保留下来,第二个带有消息“这是 3 个提交的组合。”。

在此处查看详细信息: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit


now*_*ed. 5

假设您从 06 到 10 有这些提交。

您想要将 06 后的提交合并到单个提交 ID。

commit 10
commit 09  
commit 08  
commit 07  
commit 06
Run Code Online (Sandbox Code Playgroud)

你可以做一个 git 重置软件。

git reset --soft "06"
Run Code Online (Sandbox Code Playgroud)

然后,运行以下命令将这些更改推送到远程分支。

git push origin HEAD --force
Run Code Online (Sandbox Code Playgroud)

现在,您之前所做的所有提交都应该可以作为本地更改使用,并且您可以将所有这些提交合并到一个提交中。

现在,新的提交结构应如下所示:

commit <new_commit_containing_all_7_8_9_10>
commit 06
Run Code Online (Sandbox Code Playgroud)