我曾经问过如何压缩git存储库中的前两次提交。

虽然这些解决方案相当有趣,而且不像git中的其他一些东西那样令人费解,但如果您需要在项目开发过程中多次重复这个过程,那么它们仍然是一个众所周知的伤害。

所以,我宁愿只经历一次痛苦,然后能够永远使用标准的交互式rebase。

那么,我想做的是有一个空的初始提交,它的存在仅仅是为了成为第一个。没有代码,什么都没有。只是占地方,这样就可以做地基了。

我的问题是,有了一个现有的存储库,我如何在第一个提交之前插入一个新的空提交,并将其他所有人向前移动?


当前回答

Git将——root——重基到$emptyrootcommit

应该很容易做到吗

其他回答

以下是我的bash脚本基于肯特的回答与改进:

it checks out the original branch, not just master, when done; I tried to avoid the temporary branch, but git checkout --orphan only works with a branch, not detached-head state, so it's checked out long enough to make the new root commit and then deleted; it uses the hash of the new root commit during the filter-branch (Kent left a placeholder in there for manual replacement); the filter-branch operation rewrites only the local branches, not remotes too the author and committer metadata is standardised so that the root commit is identical across repositories.


#!/bin/bash

# Save the current branch so we can check it out again later
INITIAL_BRANCH=`git symbolic-ref --short HEAD`
TEMP_BRANCH='newroot'

# Create a new temporary branch at a new root, and remove everything from the tree
git checkout --orphan "$TEMP_BRANCH"
git rm -rf .

# Commit this empty state with generic metadata that will not change - this should result in the same commit hash every time
export GIT_AUTHOR_NAME='nobody'
export GIT_AUTHOR_EMAIL='nobody@example.org'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
git commit --allow-empty -m 'empty root'
NEWROOT=`git rev-parse HEAD`

# Check out the commit we just made and delete the temporary branch
git checkout --detach "$NEWROOT"
git branch -D "$TEMP_BRANCH"

# Rewrite all the local branches to insert the new root commit, delete the 
# original/* branches left behind, and check out the rewritten initial branch
git filter-branch --parent-filter "sed \"s/^\$/-p $NEWROOT/\"" --tag-name-filter cat -- --branches
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git checkout "$INITIAL_BRANCH"

我知道这篇文章很旧了,但当谷歌搜索“插入提交git”时,这个页面是第一个。

为什么要把简单的事情变得复杂?

你有A-B-C,你想要A-B-Z-C。

git rebase -i trunk(或B之前的任何东西) 更改pick在B行上编辑 进行更改:git add .. git commit (git commit - modify将编辑B而不创建Z)

[你可以在这里进行任意数量的git提交,以插入更多的提交。]当然,在第5步中您可能会遇到麻烦,但是使用git解决合并冲突是您应该具备的技能。如果没有,那就练习!]

Git rebase—继续

很简单,不是吗?

如果你理解git rebase,添加一个“根”提交应该不是问题。

玩得开心!

切换根提交。

首先,创建您想要作为第一个提交的提交。

其次,使用以下命令切换提交顺序:

Git rebase -i—root

在根节点提交之前,会出现一个编辑器,比如:

选择1234旧根消息

在中间提交

选择你想放在根目录下的5678提交

然后,您可以将您想要的提交放在第一行中。在这个例子中:

选择你想放在根目录下的5678提交

选择1234旧根消息

在中间提交

退出编辑器,提交顺序将会改变。

PS:要更改git使用的编辑器,运行:

Git配置——全局核心。编辑name_of_the_editor_program_you_want_to_use

遵循亚里士多德和其他人的回答,但使用更简单的命令

zsh% git checkout --orphan empty     
Switched to a new branch 'empty'
zsh% git rm --cached -r .
zsh% git clean -fdx
zsh% git commit --allow-empty -m 'initial empty commit'
[empty (root-commit) 64ea894] initial empty commit
zsh% git checkout master
Switched to branch 'master'
zsh% git rebase empty
First, rewinding head to replay your work on top of it...
zsh% git branch -d empty 
Deleted branch empty (was 64ea894).

请注意,您的回购不应该包含任何等待提交的本地修改。 注意git检出——孤儿将在新版本的git中工作,我猜。 注意,大多数时候git状态给出了有用的提示。

我很兴奋,写了一个“幂等”版本的这个不错的脚本…它总是插入相同的空提交,如果你运行它两次,它不会每次都改变你的提交哈希值。所以,这是我对git-insert-empty-root的看法:

#!/bin/sh -ev
# idempotence achieved!
tmp_branch=__tmp_empty_root
git symbolic-ref HEAD refs/heads/$tmp_branch
git rm --cached -r . || true
git clean -f -d
touch -d '1970-01-01 UTC' .
GIT_COMMITTER_DATE='1970-01-01T00:00:00 +0000' git commit \
  --date='1970-01-01T00:00:00 +0000' --allow-empty -m 'initial'
git rebase --committer-date-is-author-date --onto $tmp_branch --root master
git branch -d $tmp_branch

它值得额外的复杂性吗?也许不是,但我会用这个。

这也应该允许在几个克隆的repo副本上执行这个操作,并最终得到相同的结果,因此它们仍然是兼容的…测试……是的,它可以工作,但也需要删除和添加你的遥控器,例如:

git remote rm origin
git remote add --track master user@host:path/to/repo