是否可以使用交互式git rebase从历史记录中删除文件?

ifmq2ha2  于 2022-12-17  发布在  Git
关注(0)|答案(4)|浏览(127)

在我的本地仓库中有一个旧的提交添加了一些文件,其中包括一个名为“unwanted.txt”的文件。在后续的提交中,该文件和其他文件沿着被修改。是否可以使用交互式git rebase从历史记录中完全删除文件“unwanted.txt”?我知道使用“git filter-branch”是可以做到的,但由于我正在学习git,我想了解“git rebase -i”的全部潜力,我想知道这个命令是否可以用于这样的操作。

7lrncoxx

7lrncoxx1#

你应该可以通过编辑违规提交(即rebase todo列表中提交前的eedit),然后像这样删除该文件:

git rm unwanted.txt
git commit --amend
git rebase --continue

这可能会在以后修改文件的提交中产生冲突,但这应该通过再次删除文件并继续变基来轻松解决。

编辑:你很可能还需要确保没有分支指向任何仍然存在不需要的文件的提交,并运行git gc来清除repo中的unreferences blob。如果它是一个不与任何人共享的纯私有repo,这应该不是一个问题。

0qx6xfy6

0qx6xfy62#

这在理论上是可能的,但实际上通常太痛苦了。
方法在rebase和filter-branch中是一样的,如果你意识到交互式rebase的全部就是git cherry-pick,就像它是类固醇一样,这可能会有所帮助;而git filter-branch仅仅是跨多个分支并具有合并保留的自动化的额外复杂的变基。
和往常一样,git的主要工作是操作提交图,添加新的提交,这些提交看起来像现有的提交,但有一些改变--在本例中,是那些提交所附的树。(只要一个提交不同,它就会得到一个不同的SHA-1,这意味着所有 * 后续 * 提交也必须改变,以列出随着新提交图的增长而出现的不同SHA-1。)
要了解它是如何工作的,先画一个提交图,你需要一个相当完整的图,这取决于你需要回到多久之前才能看到unwanted.txt文件,但我只画一个简单的图,只有一个命名的分支master

I - A - B - C - F   <-- master
      \       /
        D - E

这里I是初始提交;为了简单起见,我们假设它没有不需要的文件,我们假设这个文件是在提交A时引入的,并在CE中修改过。
我们需要做的是:
1.复制提交I的所有文件(保留提交者和提交者,日期戳等),同时删除不需要的文件,也就是说,如果需要的话,修改I的源代码树,这样我们就可以保留提交I的原始SHA-1。
1.删除不需要的文件时复制提交A的所有文件。这会产生一个新的,不同的提交A',因为我们将A的树更改为删除了文件的新树。由于新提交与旧提交不同,我们获得了新的SHA-1加密校验和。因此,我们在Map中保存一个条目,该条目为“旧提交A被新提交A'替换。
1.复制所有的commit B,同时删除不需要的文件。这将改变树(记住,每个commit都有整个源的完整快照,所以不需要的文件在原始的B中)。创建一个新的commit B',它具有改变的树 并将commit A'作为其父ID。
1.复制提交的所有文件C,同时删除不需要的文件,导致C'
1.复制所有提交D和我们的修改,得到D'.(注意,我们不能复制F,直到我们复制了它在图中的所有前辈,在本例中是CE.)
1.复制所有提交的E和我们的修改。
1.复制所有修改后的提交F,新的提交F'有两个父提交C'E';我们使用我们沿着在构建的SHA-1Map来找到这些。
1.最后,将master改为指向提交F',放弃原来的提交F
这将产生如下所示的图形:

A - B - C - F    [abandoned]
   /  \       /
  /     D - E
 /
I - A' - B' - C' - F'   <-- master
       \         /
         D' - E'

使用--preserve-merges的交互式重定基可以处理这种特殊情况,但是如果有多个分支,您必须根据需要使用--onto对额外的分支进行重定基,以利用新提交,您必须将新提交与旧提交相匹配,最有可能的方法是使用您手动构建的SHA-1Map文件。
还有一个额外的问题,git commit默认情况下拒绝进行“空”提交,其中“空”被定义为“与前一次提交具有相同的树”(并且不是合并)。filter-branch脚本会自动为您处理这个问题,如果选择删除空提交,则将多个新提交Map到单个旧提交(* 仅 * 修改不想要的文件的提交在前一次提交和新提交都给予不想要的文件时变为空).交互式变基在保留合并时不能很好地处理这一点,因此会带来更多的痛苦.
还有其他一些细微的区别:例如,当rebase“放弃”一个提交链时,它们会保留在已被重定基的分支的“reflog”中,以及HEAD的reflog中。它会把所有的引用复制到一个子名称空间refs/original/中,当你想要清除旧的、被放弃的提交时,这些都很重要:使用rebase,您可以使旧的引用“过期”,但是使用filter-branch,您可以强制删除原始引用。

zaqlnxep

zaqlnxep3#

在我的例子中,我必须'add'文件才能在它上面使用git rm -f,这是因为当执行带提交删除的重定基时,文件不再存在于目录中。

git add path/to/file
git rm -f path/to/file
ekqde3dh

ekqde3dh4#

如果它是一个完整的文件,你想删除,你也可以这样做:

rm unwanted.txt
git add unwanted.txt
git commit -m "remove unwanted file"
git rebase -i HEAD~<number_of_commit ahead>

然后在交互式重定基中,你移动并修正“删除不需要的文件”提交,如下所示:

pick e33adb3 commit with unwanted file
f 095204f remove unwanted file
pick 54caa68 another commit
pick 6e03883 another commit
pick aa3d754 another commit

相关问题