我想要的类似于this question。但是,我希望拆分成单独存储库的目录仍然是该存储库中的一个子目录:
我有这个:
foo/
.git/
bar/
baz/
qux/
我想把它分成两个完全独立的存储库:
foo/
.git/
bar/
baz/
quux/
.git/
qux/ # Note: still a subdirectory
如何在git中做到这一点?
如果有某种方法可以将所有新存储库的内容移到一个子目录中,那么我可以使用this answer中的方法。
发布于 2011-11-01 21:01:57
这就是当我自己解决这个问题时,我最终做的事情:
git filter-branch --index-filter \
'git ls-tree --name-only --full-tree $GIT_COMMIT | \
grep -v "^directory-to-keep$" | \
sed -e "s/^/\"/g" -e "s/$/\"/g" | \
xargs git rm --cached -r -f --ignore-unmatch \
' \
--prune-empty -- --all
这个解决方案是基于Jefromi的回答和Detach (move) subdirectory into separate Git repository,再加上很多关于SO的评论。
Jefromi的解决方案对我不起作用的原因是,我的存储库中有文件和文件夹的名称包含特殊字符(主要是空格)。此外,git rm
还抱怨不匹配的文件(使用--ignore-unmatch
解决)。
您可以保持过滤对不在存储库的根目录中或被四处移动的目录的不可知性:
grep --invert-match "^.*directory-to-keep$"
最后,您可以使用它来筛选出文件或目录的固定子集:
egrep --invert-match "^(.*file-or-directory-to-keep-1$|.*file-or-directory-to-keep-2$|…)"
要在之后进行清理,可以使用以下命令:
$ git reset --hard
$ git show-ref refs/original/* --hash | xargs -n 1 git update-ref -d
$ git reflog expire --expire=now --all
$ git gc --aggressive --prune=now
发布于 2013-08-16 04:50:39
我想做类似的事情,但是因为我想保留的文件列表很长,所以使用无数grep来做这件事是没有意义的。我写了一个从文件中读取文件列表的脚本:
#!/bin/bash
# usage:
# git filter-branch --prune-empty --index-filter \
# 'this-script file-with-list-of-files-to-be-kept' -- --all
if [ -z $1 ]; then
echo "Too few arguments."
echo "Please specify an absolute path to the file"
echo "which contains the list of files that should"
echo "remain in the repository after filtering."
exit 1
fi
# save a list of files present in the commit
# which is currently being modified.
git ls-tree -r --name-only --full-tree $GIT_COMMIT > files.txt
# delete all files that shouldn't be removed
while read string; do
grep -v "$string" files.txt > files.txt.temp
mv -f files.txt.temp files.txt
done < $1
# remove unwanted files (i.e. everything that remained in the list).
# warning: 'git rm' will exit with non-zero status if it gets
# an invalid (non-existent) filename OR if it gets no arguments.
# If something exits with non-zero status, filter-branch will abort.
# That's why we have to check carefully what is passed to git rm.
if [ "$(cat files.txt)" != "" ]; then
cat files.txt | \
# enclose filenames in "" in case they contain spaces
sed -e 's/^/"/g' -e 's/$/"/g' | \
xargs git rm --cached --quiet
fi
令人惊讶的是,这项工作比我最初预期的要多得多,所以我决定把它贴在这里。
发布于 2016-05-21 00:05:17
一种更干净的方法:
git filter-branch --index-filter '
git read-tree --empty
git reset $GIT_COMMIT path/to/dir
' \
-- --all -- path/to/dir
或者只使用核心命令,在git read-tree --prefix=path/to/dir/ $GIT_COMMIT:path/to/dir
中执行重置。
在rev-list args上指定path/to/dir
可以提前进行修剪,使用这么便宜的过滤器并不重要,但无论如何都可以避免浪费精力。
https://stackoverflow.com/questions/2797191
复制相似问题