Git:如何在不更改以后提交的文件/文件夹的情况下,在较旧的提交之间进行提交?

Git:如何在不更改以后提交的文件/文件夹的情况下,在较旧的提交之间进行提交?,git,commit,rebase,Git,Commit,Rebase,我有一个包含一系列提交的存储库。假设两个旧的提交是A,并且直接在C之后: A--C 在commit C中,我没有签入旧文件的新版本,而是签入了同名的全新文件 这使得提交C的差异看起来很混乱-事实上,这个差异没有意义,因为文件完全不同 我想要的是在a和C之间添加一个提交(那么我们称之为B): 在此提交B中,我想删除我用C更改的文件和文件夹 我知道,通过以下操作,我可以在a和C之间添加新的提交: git rebase --interactive A^ 然后在提交时执行“编辑” 然后 git rm

我有一个包含一系列提交的存储库。假设两个旧的提交是A,并且直接在C之后:

A--C
在commit C中,我没有签入旧文件的新版本,而是签入了同名的全新文件

这使得提交C的差异看起来很混乱-事实上,这个差异没有意义,因为文件完全不同

我想要的是在a和C之间添加一个提交(那么我们称之为B):

在此提交B中,我想删除我用C更改的文件和文件夹

我知道,通过以下操作,我可以在a和C之间添加新的提交:

git rebase --interactive A^
然后在提交时执行“编辑”

然后

git rm -rf file folder/
git commit -m "B" # New commit with name B
我现在如何获得相同的文件和文件夹,这是我在最初的提交C之后,也就是说在B就位之前拥有的文件和文件夹

换言之:如果没有我在B中所做的移除,我如何才能再次获得C

git checkout A
git rm -rf file folder/
git commit -m 'B'
echo 'new C commit' | git commit-tree C -p HEAD
# create a new branch/update branch with the commit id printed by commit-tree
这将:

  • 签出A(分离头)
  • 删除文件和文件夹,创建新的提交
    B
  • 使用与原始提交C相同的一组文件/状态创建新的提交
  • 然后,您必须更新旧分支以指向新提交(当前仍然是分离的头)

另一种方法可能是使用移植物,然后过滤分支使其永久化:

git checkout A
git rm -rf file folder/
git commit -m B
echo `git rev-parse C` `git rev-parse HEAD` >> .git/info/grafts
git filter-branch A^..C

以下是我为解决此问题所做的步骤:

git checkout A
git rm -rf file folder/
# Create a new commit with name B on top of A:
git commit -m "B"
# On top of B create a new commit with what was C:
echo 'new C commit' | git commit-tree C^{tree} -p HEAD 
这将创建一个新的C提交并返回其SHA哈希。此时,如果签出原始的C提交,那么新的C提交的签出正好包含您将得到的内容

git checkout new-C-commit # No, this did not happen with git commit-tree
git rebase --onto HEAD C master

这将重新调整分支(在我的例子中是主分支),从新的C提交上的原始C提交之后的第一次提交开始。这将毫无问题地应用,因为两个提交都有效地创建了相同的文件和文件夹。

如何,更新到A,提交B,在B的基础上重新设置C?或者,在A之上提交B,与C合并,然后在合并之上提交一个新的变更集来删除不需要的部分,怎么样?您真的需要更改历史记录吗?在我在A的基础上提交了B之后,我尝试了
git-rebase--HEAD A master
。这将在B的基础上重新设置C,但是(逻辑上)会产生一系列合并冲突。这是我想要避免的情况……我已经尝试了你提出的第一种方法。但是,
git提交树C-p头不起作用。它给出:致命:C不是有效的“tree”对象(事实上我已经用相应commit的commit SHA替换了命令中的“C”,这个SHA也是错误输出中提到的内容)。@Christopher:try
C^{tree}
(用commit的散列/分支名称替换C)这看起来是解决方案。我会仔细检查,然后一旦张贴的步骤,我必须做…感谢knittl设置我在正确的轨道上!他真了不起!
git checkout new-C-commit # No, this did not happen with git commit-tree
git rebase --onto HEAD C master