如何使用index-filter&co从git repo中提取具有提交历史记录的文件

pet*_*hil 41 git extraction git-filter-branch

我的情况是,我有一个git repo从SVN转换为HG到GIT,我只想提取一个源文件.我也有像aÌ(编码不匹配损坏的Unicodeä)和文件名中的空格这样奇怪的字符.

看起来并不是特别容易,这就是为什么我会回答我自己的问题,尽管有很多关于git [index-filter | subdirectory-filter | filter-tree]的类似问题,因为我需要使用前面所有的来实现这一点!

所以问题是:"如何从存储库中提取一个文件并将其放在新存储库的根目录下?"

jth*_*ill 44

一个更快速,更易于理解的过滤器,可以完成同样的事情:

git filter-branch --index-filter '
                        git read-tree --empty
                        git reset $GIT_COMMIT -- $your $files $here
                ' \
        -- --all -- $your $files $here
Run Code Online (Sandbox Code Playgroud)

  • 如何将其应用于单个分支?用` - branchname`替换` - --all`? (3认同)
  • 对我来说,这保留了触及该文件的提交,但它们都是空的,并且文件本身在其首次创建文件的提交中的*present*状态中添加(即不在它实际处于的状态时间). (3认同)
  • 这对我来说非常有效。我添加了一个“--prune-empty”参数来删除任何空提交。 (2认同)
  • 我不确定您为什么认为我使用了cmd。这实际上是在Linux上的“鱼”下。 (2认同)

pet*_*hil 13

首先快速说明,即使是在评论中将git repo中的一组文件拆分到他们自己的存储库中的一个咒语,也保留了相关的历史记录

SPELL='git ls-tree -r --name-only --full-tree "$GIT_COMMIT" | grep -v "trie.lisp" | tr "\n" "\0" | xargs -0 git rm --cached -r --ignore-unmatch'
git filter-branch --prune-empty --index-filter "$SPELL" -- --all
Run Code Online (Sandbox Code Playgroud)

将无法帮助名为like的文件imaging/DrinkkejaI<0300>$'\302\210'.txt_74x2032.gif.这aI<0300>$'\302\210'部分曾经是一封信:ä.

所以为了提取单个文件,除了filter-branch我还需要做:

git filter-branch -f --subdirectory-filter lisp/source/model HEAD
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用--tree-filter :(需要进行测试,因为该文件先前位于另一个目录中,请参阅: 如何在Git仓库中移动所有提交的目录?)

MV_FILTER='test -f source/model/trie.lisp && mv ./source/model/trie.lisp . || echo "Nothing to do."'
git filter-branch --tree-filter $MV_FILTER HEAD --all
Run Code Online (Sandbox Code Playgroud)

要查看文件的所有名称,请使用:

git log --pretty=oneline --follow --name-only git-path/to/file | grep -v ' ' | sort -u
Run Code Online (Sandbox Code Playgroud)

http://whileimautomaton.net/2010/04/03012432所述

然后按照以下步骤操作:

$ git reset --hard
$ git gc --aggressive
$ git prune
$ git remote rm origin # Otherwise changes will be pushed to where the repo was cloned from
Run Code Online (Sandbox Code Playgroud)

  • 我不确定如何遵循这些说明,这个答案的文字似乎提出了几条可能的路线.我看不到任何程序. (3认同)

Rom*_*man 11

请注意,如果将此项与将所需文件移动到新目录中的附加步骤相结合,事情会变得更加容易.

这可能是一个非常常见的用例(例如,将所需的单个文件移动到根目录).
我这样做(使用git 1.9)(首先移动文件,然后删除旧树):

git filter-branch -f --tree-filter 'mkdir -p new_path && git mv -k -f old_path/to/file new_path/'
git filter-branch -f --prune-empty --index-filter 'git rm -r --cached --ignore-unmatch old_path'
Run Code Online (Sandbox Code Playgroud)

您甚至可以轻松地将通配符用于所需的文件(无需使用grep -v).

我认为这个('mv'和'rm')也可以在一个过滤器分支中完成,但它对我没用.

我没有尝试过奇怪的角色,但我希望无论如何这都有帮助.让事情变得简单似乎对我来说总是一个好主意.

提示:
对于大型回购,这是一个耗时的操作.因此,如果你想做几个动作(比如获取一堆文件,然后在'new_path/subdirs'中重新排列它们),最好尽快做'rm'部分以获得更小更快的树.


Mar*_*nas 6

我在这里使用 git log 和 git am 找到了一个优雅的解决方案:https : //www.pixelite.co.nz/article/extracting-file-folder-from-git-repository-with-full-git-history/

万一它消失了,你可以这样做:

  1. 在原始回购中,

    git log --pretty=email --patch-with-stat --reverse --full-index --binary -- path/to/file_or_folder > /tmp/patch
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果文件位于子目录中,或者您想重命名它

    sed -i -e 's/deep\/path\/that\/you\/want\/shorter/short\/path/g' /tmp/patch
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在一个新的空仓库中

    git am < /tmp/patch
    
    Run Code Online (Sandbox Code Playgroud)


Rom*_*man 2

现在有一个新命令git filter-repo。它有更多的可能性和更好的性能。

有关详细信息,请参阅手册页,有关安装的项目页

删除除 src/README.md 之外的所有内容并将其移动到根目录:

git filter-repo --path src/README.md
git filter-repo --subdirectory-filter src/
Run Code Online (Sandbox Code Playgroud)

--path选择单个文件并将--subdirectory-filter该目录的内容移动到根目录。