如何在 Git 中的所有其他提交之前添加父提交?

如何在 Git 中的所有其他提交之前添加父提交?

我现在正尝试将一个开源项目转换为 Git,并且我最近获得了该项目的历史数据。不过,我已经对仓库进行了修改,因此我想在 git 提交到仓库时将这些早期更改添加到开始Git 中的提交树。(是的,我知道这会更改后续提交的 SHA;这是可以接受的。)数据以工作目录的连续快照形式提供。我希望设置它,以便后续提交的工作目录状态不受影响(我不想合并更改)。

例如,如果初始提交B将文件a和添加b到工作目录,而我的历史提交A添加了文件a,我想创建一个仅以添加文件B'为父级的新提交。在 和 中,工作目录看起来相同,并且任何在 之上的后续提交都可以安全地重新定位到。AbBB'BB'

可以在 Git 中执行此操作吗? 如果可以,怎么做?

编辑:请注意,我需要修改初始提交。 的标准用法是git commit将新提交作为提交的子提交附加HEAD,因此对于没有父提交的初始提交不起作用。

答案1

类似这样的事情应该有效。

# Create a new branch with the old history
$ git checkout --orphan old-history    
$ git add <old-files>
$ git commit

# Rebase master on top of the branch with old-history
$ git checkout master
$ git pull --rebase . old-history

答案2

git-filter-branch(1)手册页中有关于此内容的说明:

   To set a commit (which typically is at the tip of another history) to be
   the parent of the current initial commit, in order to paste the other
   history behind the current history:

       git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD

   (if the parent string is empty - which happens when we are dealing with
   the initial commit - add graftcommit as a parent). Note that this assumes
   history with a single root (that is, no merge without common ancestors
   happened).

采取建议肯特,您可能需要--tag-name-filter cat在此命令中添加以将标签名称重写为新提交。手册页中也有记录,并警告先备份旧标签:

       The original tags are not deleted, but can be overwritten; use
       "--tag-name-filter cat" to simply update the tags. In this case, be
       very careful and make sure you have the old tags backed up in case
       the conversion has run afoul.

手册页还解释了为什么在重写标签时必须删除签名:

       Nearly proper rewriting of tag objects is supported. If the tag has
       a message attached, a new tag object will be created with the same
       message, author, and timestamp. If the tag has a signature
       attached, the signature will be stripped. It is by definition
       impossible to preserve signatures. The reason this is "nearly"
       proper, is because ideally if the tag did not change (points to the
       same object, has the same name, etc.) it should retain any
       signature. That is not the case, signatures will always be removed,
       buyer beware. There is also no support for changing the author or
       timestamp (or the tag message for that matter). Tags which point to
       other tags will be rewritten to point to the underlying commit.

在单根示例之后,手册页继续提供多根说明:

   If this is not the case, use:

       git filter-branch --parent-filter \
               'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD

   or even simpler:

       git replace --graft $commit-id $graft-id
       git filter-branch $graft-id..HEAD

使用git filter-branch比使用更简洁,它的功能类似于和git --rebase的组合,应用diffpatch变化在每个提交中都在另一个提交之上。相反,git filter-branch保持每个提交中的实际文件不变,并直接更改父提交指针。

当然,新的提交将要具有与原始 SHA 不同的 SHA – 这是不可避免的,因为父提交包含在 SHA 计算中。


你也可以尝试 Mark Lodato 的git-reparent脚本,它似乎使用 git plumbing 命令来实现类似的结果。

答案3

我不确定是否可以这样做:

git add [files]
git commit -m 'first commit'

然后合并更改

git add [files]
git commit -m 'second commit'

然后

git push

如果这不起作用那么我认为就没有办法实现这一目标。

相关内容