我的情况是,我有一个git repo从SVN转换为HG到GIT,我只想提取一个源文件。我也有一些奇怪的字符,如aÌ(编码不匹配损坏的Unicodeä)和文件名中的空格。
似乎它并不是特别容易,这就是为什么我会回答我自己的问题,尽管有很多类似的问题关于git [index-filter |子目录 - 过滤器| filter-tree],因为我需要使用以前的所有内容实现这一点!
所以问题是:“如何从存储库中提取一个文件并将其放在新存储库的根目录下?”
答案 0 :(得分:36)
更快速,更易于理解的过滤器可以完成同样的事情:
git filter-branch --index-filter '
git read-tree --empty
git reset $GIT_COMMIT -- $your $files $here
' \
-- --all -- $your $files $here
答案 1 :(得分:13)
首先请注意,即使是对Splitting a set of files within a git repo into their own repository, preserving relevant history
的评论中的咒语也是如此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
对名为imaging/DrinkkejaI<0300>$'\302\210'.txt_74x2032.gif
的文件无效。
aI<0300>$'\302\210'
部分曾是一个字母:ä
。
因此,为了提取单个文件,除了filter-branch之外,我还需要这样做:
git filter-branch -f --subdirectory-filter lisp/source/model HEAD
或者,您可以使用--tree-filter: (需要进行测试,因为文件早先在另一个目录中,请参阅: How can I move a directory in a Git repo for all commits?)
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
要查看文件的所有名称,请使用:
git log --pretty=oneline --follow --name-only git-path/to/file | grep -v ' ' | sort -u
如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
答案 2 :(得分:10)
请注意,如果将此项与将所需文件移动到新目录中的附加步骤相结合,事情会变得容易得多。
这可能是一个非常常见的用例(例如,将所需的单个文件移动到根目录) 我这样做(使用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'
您甚至可以轻松地将通配符用于所需的文件(无需使用grep -v)。
我认为这个('mv'和'rm')也可以在一个过滤器分支中完成,但它对我没用。
我没有尝试过奇怪的角色,但我希望无论如何这都有帮助。让事情变得简单对我来说总是一个好主意。
提示:
对于大型回购,这是一个耗时的行动。所以如果你想做几个动作(比如获取一堆文件,然后在'new_path / subdirs'中重新排列它们),最好尽快做'rm'部分以获得更小更快的树。< / p>
答案 3 :(得分:4)
我在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
如果文件位于子目录中,或者要重命名
sed -i -e 's/deep\/path\/that\/you\/want\/shorter/short\/path/g' /tmp/patch
在一个新的空仓库中
git am < /tmp/patch
答案 4 :(得分:0)
以下内容将重写历史记录,并且仅保留涉及您提供的文件列表的提交。您可能希望在存储库的克隆中执行此操作,以避免丢失原始历史记录。
func main() {
gd := generateGenericData()
fmt.Println(gd)
fmt.Println(gd.(GenericData))
// Doesn't work, but is straightforward
// fmt.Println(gd.(Data))
// Works, but is not straight forward
fmt.Println(Data{gd.(GenericData).Hard, gd.(GenericData).Soft.(int)})
genDataGenerator := returnsGenericDataGenerator()
// Doesn't work, but is straightforward
//genDataGenerator.(GenericDataGenerator)()
// Works, but is not straight forward
resp := genDataGenerator.(func() interface{})()
fmt.Println(resp.(GenericData))
}
然后,您可以根据用例通过常规的FILES='path/to/file1 other-path/to/file2 file3'
git filter-branch --prune-empty --index-filter "
git read-tree --empty
git reset \$GIT_COMMIT -- $FILES
" \
-- --all -- $FILES
或merge
命令将该新分支合并到目标存储库中。