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)
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)
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'部分以获得更小更快的树.
我在这里使用 git log 和 git am 找到了一个优雅的解决方案:https : //www.pixelite.co.nz/article/extracting-file-folder-from-git-repository-with-full-git-history/
万一它消失了,你可以这样做:
在原始回购中,
git log --pretty=email --patch-with-stat --reverse --full-index --binary -- path/to/file_or_folder > /tmp/patch
Run Code Online (Sandbox Code Playgroud)如果文件位于子目录中,或者您想重命名它
sed -i -e 's/deep\/path\/that\/you\/want\/shorter/short\/path/g' /tmp/patch
Run Code Online (Sandbox Code Playgroud)在一个新的空仓库中
git am < /tmp/patch
Run Code Online (Sandbox Code Playgroud)现在有一个新命令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
该目录的内容移动到根目录。