如何压缩所有的git提交到一个?

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

我可以重新进行第一次提交,但这会使我有2次提交。 有没有办法在第一个之前引用提交?

也许最简单的方法就是创build一个工作副本当前状态的新的存储库。 如果你想保留所有的提交信息,你可以先做git log > original.log ,然后在新的仓库中编辑你的初始提交信息:

 rm -rf .git git init git add . git commit 

要么

 git log > original.log # edit original.log as desired rm -rf .git git init git add . git commit -F original.log 

在最近的git版本中,你可以使用git rebase --root -i

对于除第一个之外的每个提交,都要改变为squash

更新

我做了一个别名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" 

注意 :记得提供注释,否则将使用默认提交消息“新开始”。

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

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

一个class轮

 git reset $(git commit-tree HEAD^{tree} -m "A new start") 

注意 :这里“ A new start ”只是一个例子,随意使用你自己的语言。

TL; DR

不需要压缩,使用git commit-tree来创build一个孤立的提交,并与它一起去。

说明

  1. 通过git commit-tree创build一个单独的提交

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

    基于提供的树对象创build一个新的提交对象,并在stdout上发出新的提交对象ID。 日志消息是从标准input读取的,除非给出-m或-F选项。

    expression式HEAD^{tree}表示与HEAD对应的树对象,即当前分支的顶端。 请参阅树对象和提交对象 。

  2. 重置当前分支到新的提交

    然后git reset只需重置当前分支到新创build的提交对象。

这样,工作空间中的任何东西都不会被触动,也不需要变形/压扁,这使得它非常快速。 而所需的时间与资源库大小或历史深度无关。

变化:来自项目模板的新回购

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

 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") 

这避免了添加模板回购作为一个远程( origin或其他)和折叠模板回购的历史到您的初始提交。

如果你只想把所有的提交压缩到根提交,然后

 git rebase --interactive --root 

可以工作,对于大量提交(例如,数百次提交)是不切实际的,因为重新分配操作可能运行得非常慢,以生成交互式重新分配编辑器提交列表,以及自行运行重新分配。

当你压扁大量的提交时,这里有两个更快更有效的解决scheme:

替代解决scheme#1:孤立分行

您可以简单地在当前分支的提示(即最近的提交)中创build一个新的孤立分支。 这个孤立分支形成一个全新的独立的提交历史logging树的初始根提交,这实际上相当于压扁所有的提交:

 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 

文档:

  • git-checkout(1)手册页 。

替代解决scheme#2:软复位

另一个有效的解决scheme是简单地对根提交使用混合或软重置<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 

文档:

  • git-reset(1)手册页 。
 echo "message" | git commit-tree HEAD^{tree} 

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

 git reset SHA-1 

最简单的方法是使用“pipe道”命令update-ref删除当前分支。

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

这会让您回到“初始提交”状态,您可以从新的初始提交开始。

 git update-ref -d refs/heads/master git commit -m "New initial commit" 

以下是我如何做到这一点,以防万一它为别人工作:

请记住,做这样的事情总是有风险的,在开始之前创build一个保存分支是一个不错的主意。

从logging开始

 git log --oneline 

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

 git reset --soft <#sha#> 

<#sha#>replace为从日志中复制的SHA

 git status 

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

 git commit --amend 

修改当前首次提交的所有当前更改

现在强行推这个分支,它会覆盖那里的东西。

首先,使用git rebase --interactive所有提交压缩到一个提交中。 现在你剩下两个提交壁球了。 要做到这一点,阅读任何

  • 我如何结合Git仓库的前两个提交?
  • git:如何挤压前两个提交?

我读了一些关于使用移植,但从来没有调查过多。

无论如何,你可以像这样手动压缩最后2次提交:

 git reset HEAD~1 git add -A git commit --amend 

假设除了创build一个提交(no-parents no-history)之外, 需要保留提交的所有提交数据:

  • 作者(姓名和电子邮件)
  • 创作date
  • 提交者(姓名和电子邮件)
  • 承诺date
  • 交付日志消息

当然,new / single commit的commit-SHA将会改变,因为它代表一个新的(非)历史,成为一个无父/ root提交。

这可以通过阅读git log和设置一些variables为git commit-tree 。 假设你想在一个新的分支one-commit提交中从master创build一个单一one-commit ,保留上面的提交数据:

 git checkout -b one-commit master ## create new branch to reset git reset --hard \ $(eval "$(git log master -n1 --format='\ COMMIT_MESSAGE="%B" \ GIT_AUTHOR_NAME="%an" \ GIT_AUTHOR_EMAIL="%ae" \ GIT_AUTHOR_DATE="%ad" \ GIT_COMMITTER_NAME="%cn" \ GIT_COMMITTER_EMAIL="%ce" \ GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE $COMMIT_MESSAGE COMMITMESSAGE ') 

用移植物挤压

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

git log现在将从该提交开始

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