【问题标题】:How to move a file from one git repository to another while preserving history如何在保留历史记录的同时将文件从一个 git 存储库移动到另一个
【发布时间】:2012-05-18 11:15:56
【问题描述】:

我正在尝试将单个文件(称为 foo.txt)从一个存储库移动到另一个(不相关的)存储库,并保留其历史记录。 ebneter's question 显示如何对子目录执行此操作。 taw's question 有一些提示和建议,但不是一个循序渐进的过程。 jkeating's question 看起来很有希望,但对我不起作用。对于这个特定的用例,谷歌搜索是空的。我正在寻找的是完成此任务的明确命令序列。

我开始执行的命令顺序是这样的:

$ git clone source-repo/ source-repo-copy
$ cd source-repo-copy
$ git filter-branch --tree-filter 'test ! "$@" = "foo.txt" && \
  git rm --cached --ignore-unmatch $@ || true' --prune-empty

我的过滤命令的逻辑是git rm所有不是foo.txt的文件。我在命令中添加了|| true,以强制它具有零返回值以满足过滤器分支。

我的意图是将 source-repo-copy 设置为我的目标存储库 (target-repo) 的远程,并假设 git filter-branch 过滤掉除 foo.txt 之外的所有内容,获取并将 source-repo-copy 合并到 target-回购。不幸的是,git filter-branch 命令似乎没有任何效果。它运行时没有出现任何错误,并且似乎通过了 source-repo 中的 600 多个提交,但是当它完成时,git log 和 source-repo-copy 中的文件看起来是一样的。除了 foo.txt 之外的所有文件都不应该丢失,并且所有没有触及它的提交都应该从日志中消失吗?

此时我不知道如何继续。有什么建议吗?

【问题讨论】:

标签: git git-filter-branch


【解决方案1】:

这对我有用,但有一个完整的目录。

如图here

~$ cd neu
~/neu$ git filter-branch --subdirectory-filter FooBar HEAD
~/neu$ git reset --hard
~/neu$ git remote rm origin
~/neu$ rm -r .git/refs/original/
~/neu$ git reflog expire --expire=now --all
~/neu$ git gc --aggressive
~/neu$ git prune
~/neu$ git remote add origin git://github.com/FooBar/neu.git

编辑:对于单个文件:

先过滤目录:

 git filter-branch --prune-empty --subdirectory-filter myDirectory -- --all

过滤单个文件:

 git filter-branch -f --prune-empty --index-filter "git rm --cached --ignore-unmatch $(git ls-files | grep -v 'keepthisfile.txt')"

做一些清理工作:

 git reset --hard
 git gc --aggressive
 git prune

应该这样做。

【讨论】:

  • 是的,--subdirectory-filter 的示例看起来都很简单,但我希望移动单个文件,而不是子目录。有什么想法吗?
  • 请先在 testrepo 上试用,新的解决方案适合我
  • 我按照您的建议过滤了目录,使用“。”而不是“我的目录”。我在目录中留下了零个文件(只是.git)。 git log 仅显示合并提交(其中 12 个)。然后我过滤了单个文件。我收到了错误,因为 git rm 被调用时使用了一个空参数列表。我在命令末尾添加了|| true,以防止 git rm 的抱怨中止过滤器。之后,仍然是零文件,git log 中只有 4 次合并提交。我完成了git reset/gc/prune,但没有看到任何变化。我猜它没有工作。 :(我很高兴我在测试回购中尝试了这个。:)
  • 请在 github 上上传一个带有你的结构的 testrepo 或其他东西。 (或者告诉我层次结构)。如果 git 包含 testDir/myFile{1..3}.txt 它可以正常工作。如果您的目录为空,则单个文件的过滤器不起作用,请尝试忽略目录过滤器并踩过滤器。您的 shell 可能无法很好地识别该命令。 git filter-branch -f --prune-empty --index-filter 'git rm --cached --ignore-unmatch $(git ls-files | grep -v "keepFile.txt")'
  • 起初我并不清楚针对单个文件而不是目录采取的步骤。这是我的理解,对于任何同样困惑的人:EDIT 中的两个 filter-branch 命令应该替换原始代码中的一个 filter-branch 命令。然后,“做一些清理”命令实际上包含在原始代码部分的其余部分中,应该这样运行。最后需要git push origin new-branch
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
  • 2019-10-13
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多