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

我可以将base转换为第一次提交,但这将留给我2次提交。 有没有办法在第一个提交之前引用这个提交?


当前回答

一个衬套

你可以直接从HEAD创建一个squash-all commit,完全不需要rebase,只需要运行:

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

在~/.gitconfig中创建别名

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} \"$@\");};f"

然后只要运行:git squash-all -m“一个全新的开始”

注意:要么从标准输入提供提交消息,要么通过-m/-F选项,就像git commit命令一样。参见git-commit-tree手册。

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

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} "$@");};f'

解释

create a single commit via git commit-tree What git commit-tree HEAD^{tree} -m "A new start" does is: Creates a new commit object based on the provided tree object and emits the new commit object id on stdout. The log message is read from the standard input, unless -m or -F options are given. The expression HEAD^{tree} represents the tree object corresponding to HEAD, namely the tip of your current branch. see Tree-Objects and Commit-Objects. reset the current branch to the new commit Then git reset simply reset the current branch to the newly created commit object. This way, nothing in the workspace is touched, nor there's need for rebase/squash, which makes it really fast. And the time needed is irrelevant to the repository size or history depth.


变体:项目模板中的新回购

这对于在新项目中使用另一个存储库作为模板/原型/种子/框架创建“初始提交”非常有用。例如:

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

这避免了将模板回购作为远程(源或其他)添加,并将模板回购的历史记录折叠到初始提交中。

其他回答

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

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

这会让你回到“初始提交”状态,在那里你可以开始一个新的初始提交。

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

一行6个字:

git checkout --orphan new_root_branch  &&  git commit

这个答案改进了上面的几个(请投票),假设除了创建一个提交(no-parents - no-history),你还想保留该提交的所有提交数据:

作者(姓名及邮箱) 撰写日期 提交人(姓名及邮箱) 提交日期 提交日志消息

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

这可以通过读取git日志并为git提交树设置一些变量来实现。假设你想在一个新的分支one-commit中从master创建一个单独的提交,保留上面的commit-data:

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 merge origin/master && git reset --soft origin/master

前面的合并cmd确保,在提交时,没有来自master的最近更改会出现在您的头上!之后,只需提交更改并执行git push -f

当我从git存储库恢复模板时,我通常会压缩整个树,以获得更干净的历史记录,并确保合法合规。我的工作流程是这样的:

git clone https://git.invalid/my-awesome-template.git my-awesome-foo
cd !$
git branch -M master my-awesome-template/master
git checkout --orphan master
git rm -rf /
git commit --allow-empty --allow-empty-message -m 'Initial commit'
git merge --squash --allow-unrelated-histories my-awesome-template/master
git commit
git branch -D my-awesome-template/master
# you can now `drop' that "Initial commit":
git rebase -i --root

这将把整个历史记录压缩到一个大的提交消息中。

在这个例子中:

Master是工作分支 My-awesome-template /master是一个中间分支