【问题标题】:How to remove previously added git subtree and its history如何删除以前添加的 git 子树及其历史记录
【发布时间】:2014-11-24 07:29:38
【问题描述】:

很多个月前,我在git 存储库中添加了一个子树。该子树包括几个文件夹和文件。我添加了子树而不是创建子模块(如推荐的那样)。现在我意识到我只想要子树中的一个文件,其余的都不想要。更糟糕的是,当其他人clone我的存储库时,他们得到的不是预期的——与我创建的子树和其他代码存在一些冲突。

我可以使用

获取文件/文件夹
git rm subtree–folder1 subtree_folder2 subtree_files.*

但是,我仍然留下了来自子树的冗长提交历史。

自从我最初添加子树以来,我已经进行了大量的开发,并且不能丢失我生成的提交历史记录。

简而言之,这就是我想要的:

  1. 删除所有子树文件/文件夹。
  2. 忘记所有子树提交的历史记录。
  3. 只留下我的代码和我的历史记录。

这可能吗?

PS。一种可能的复杂情况是,我将要保留的单个头文件从子树移到了代码中的某个文件夹中。我希望这不是让我忘记子树历史的原因。

一次尝试

从远程服务器重新结帐后,我得到以下信息:

$ ls
.git             CMakeLists.txt   Read.cpp         logging.conf
.gitignore       ENDF6            TestData         src
.sparse-checkout LICENCE          doc              test
.travis.yml      README.md        include          tools

.gitignore 只有: 建造/ 调试/

当我按照建议尝试命令时,我没有得到非常满意的响应:

$ git filter-branch --index-filter 'git rm --cached -rf test tools src doc LICENCE README.md .travis.yml' HEAD
Rewrite 2fec85e41e40ae18efd1b130f55b14166a422c7f (1/1701)fatal: pathspec 'test' did not match any files
index filter failed: git rm --cached -rf test tools src doc LICENCE README.md .travis.yml

我不知道为什么它说它与test 存在问题,但它显然存在。我很困惑。

【问题讨论】:

  • 您是否尝试过简单地使用git rm <subtree name> 删除子树?
  • @hunch_hunch 我这样做了,这里的命令也一样:stackoverflow.com/questions/15890047/… 但我仍然拥有子树的所有历史记录。救命!
  • 您可以通过 rebase 或 filter-branch 重写您的存储库历史记录吗?
  • @AndrewC 只要我保留更改的历史记录,我就可以重写我的存储库历史记录。
  • 您是否尝试过树或索引过滤操作? kernel.org/pub/software/scm/git/docs/git-filter-branch.html

标签: git git-subtree


【解决方案1】:

您需要使用 filter-branch 和 --prune-empty 选项来删除任何不再引入新更改的提交。

git filter-branch --index-filter 'git rm --cached --ignore-unmatch -rf dir1 dir2 dirN file1 file2 fileN' --prune-empty -f HEAD

之后,如果要恢复磁盘空间,则需要删除过滤器分支保存的所有原始 refs,使 reflog 过期,并进行垃圾回收。

【讨论】:

  • 感谢您的帮助!这里没有显示,但在我们的聊天中@AndrewC 提供了所需的答案。
  • @SkylarSaveland 看到chat jlconlin 指的是,虽然它应该是这里的解决方案。嗯
  • 这是正确的答案:git filter-branch --index-filter 'git rm --cached --ignore-unmatch -rf dir1 dir2 dirN file1 file2 fileN' --prune-empty -f HEAD? @AndrewC 如果答案不正确,您能否更新答案或发表评论?
  • @fuzzyTew 如果您查看评论/聊天历史记录,您会发现它适用于 OP。也就是说,filter-branch 最近已被 'filter-repo' 命令取代,因此如果您现在开始,您可能需要考虑这一点。
  • 我推断您一定是前段时间从聊天中更新了答案。伟大的。 filter-repo 现在。
【解决方案2】:

您可以使用git filter-branch 将操作应用于您在分支中所做的所有提交。这包括在您重写整个历史记录时从每次提交中删除文件。此处提供了很好的描述和说明:http://gitready.com/beginner/2009/03/06/ignoring-doesnt-remove-a-file.html。您可能会发现以下问题也很有用:Completely remove files from Git repo and remote on GitHub(这是我找到链接的地方)。您将使用此解决方案运行的实际命令类似于git filter-branch --index-filter 'git rm --cached -rf subtree–folder1 subtree_folder2' HEAD

另一种可能对你正在做的事情有点过分的方法是挑选樱桃。 Cherry-picking 让你可以用你喜欢的任何细节级别重写你喜欢的任何历史部分:http://git-scm.com/docs/git-cherry-pick。你会想做git reset --hard <HASH of commit that introduced the subtree>之类的事情,然后是一系列的

git cherry-pick -n <following commit hashes>
git reset
git add -p
git commit

对于您所做的每个后续提交。这将允许您从过去所做的每个提交中删除子树。您可以参考partly cherry-picking a commit with git 了解有关有效采摘樱桃的更多信息。完成此版本的删除后,您将需要删除不再属于您的分支的旧提交:

git reflog expire --expire-unreachable=now --all
git gc --prune=now

其他参考问题: How to move a branch backwards in git? Listing and deleting Git commits that are under no branch (dangling?)

【讨论】:

    猜你喜欢
    • 2013-03-31
    • 1970-01-01
    • 2017-06-16
    • 2011-03-10
    • 2020-12-28
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    相关资源
    最近更新 更多