如何提取git子目录并从中生成子模块?
几个月前我启动了一个项目,并将所有内容存储在主目录中。 在我的主目录“Project”中有几个包含不同内容的子目录: 项目/文件包含用LaTeX编写的文档 Project/sourcecode/RailsApp包含my rails应用程序如何提取git子目录并从中生成子模块?,git,git-submodules,Git,Git Submodules,几个月前我启动了一个项目,并将所有内容存储在主目录中。 在我的主目录“Project”中有几个包含不同内容的子目录: 项目/文件包含用LaTeX编写的文档 Project/sourcecode/RailsApp包含my rails应用程序 “项目”是数字化的,在“paper”和“RailsApp”目录中都有很多提交。现在,由于我想在我的“RailsApp”中使用cruisecontrol.rb,我想知道是否有一种方法可以在不丢失历史记录的情况下从“RailsApp”生成子模块。如果你想将一些文件
“项目”是数字化的,在“paper”和“RailsApp”目录中都有很多提交。现在,由于我想在我的“RailsApp”中使用cruisecontrol.rb,我想知道是否有一种方法可以在不丢失历史记录的情况下从“RailsApp”生成子模块。如果你想将一些文件的子集传输到一个新的存储库,但保留历史记录,你基本上会得到一个全新的历史记录。其工作方式基本如下:
foodir/
是其项目根目录,并放弃所有其他历史记录:
git filter-branch --subdirectory-filter foodir -- --all
因此,例如,您可以将库子目录转换为自己的存储库。注意将
--
过滤器分支选项与修订选项分开的--
,以及重写所有分支和标记的--all
实现这一点的一种方法是相反的-删除除要保留的文件以外的所有内容 基本上,复制存储库,然后使用删除除要保留的文件/文件夹以外的所有内容 例如,我有一个项目,希望从中将文件
tvnamer.py
提取到一个新的存储库:
git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD
它使用git filter branch--tree filter
完成每个提交,运行命令并重新提交结果目录内容。这是极具破坏性的(因此您应该只在存储库的副本上执行此操作!),并且可能需要一段时间(对于包含300个提交和大约20个文件的存储库,大约需要1分钟)
上面的命令只是在每个修订版上运行以下shell脚本,当然您必须对其进行修改(使其排除子目录而不是tvnamer.py
):
最大的明显问题是它会留下所有提交消息,即使它们与剩余文件无关。脚本修复了这个
git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'
您需要将-f
强制参数run过滤器分支
再次与refs/original/
中的任何内容一起使用(这基本上是一个备份)
当然,这永远不会是完美的,例如,如果您的提交消息提到其他文件,但它与git current所允许的最接近(据我所知)
同样,只能在存储库的副本上运行此操作-总之,要删除除“ThismyFileName.txt”以外的所有文件:
现在有一种比手动使用git filter branch更简单的方法: 装置 注意
git子树
现在是从1.7.11开始的git
(如果您安装了contrib)的一部分,因此您可能已经安装了它。您可以通过执行git子树
进行检查
要从源代码安装git子树(对于较旧版本的git): 或者如果你想要手册页等等
make doc
make install
用法
将较大的数据块拆分为较小的数据块:
# Go into the project root
cd ~/my-project
# Create a branch which only contains commits for the children of 'foo'
git subtree split --prefix=foo --branch=foo-only
# Remove 'foo' from the project
git rm -rf ./foo
# Create a git repo for 'foo' (assuming we already created it on github)
mkdir foo
pushd foo
git init
git remote add origin git@github.com:my-user/new-project.git
git pull ../ foo-only
git push origin -u master
popd
# Add 'foo' as a git submodule to `my-project`
git submodule add git@github.com:my-user/new-project.git foo
有关详细文档(手册页),请阅读git subtree.txt
,两者的答案非常相似。我在两人之间来回奔波,试图理解其中任何一人身上缺失的部分。下面是它们的组合
首先将Git Bash导航到要拆分的Git回购的根目录。在我的示例中,这是~/Documents/OriginalRepo(master)
下面是上面的一个副本,替换了可自定义的名称,并改用https。根文件夹现在是~/Documents/\u Shawn/UnityProjects/SoProject(master)
这也是一个很好的答案:git子树可能与之重复,但这不是避免使用子模块的关键吗?我的意思是,您确实是git子树的作者(除非有昵称冲突),但是看起来git子树已经改变了,尽管您显示的命令似乎仍然有效。我说得对吗?从1.7.11开始,git子树现在是git的一部分(如果您安装contrib的话)。Well
git rm-rf./foo
从HEAD
中删除foo
,但不过滤我的项目的全部历史记录。然后,git子模块添加git@github.com:my user/new-project.git foo
仅使foo
成为从头部开始的子模块。在这方面,脚本过滤器分支
更为优越,因为它允许实现“从一开始就好像subdir是一个子模块一样”的thx——git子树文档有点令人困惑,这是(对我来说)我想用它做的最明显的有用的事情……看起来这只是Mac:(git filter分支
有(现在?)一个删除空提交的内置选项,即--prune empty
。git过滤器分支
的一个更好的指南是在这个问题的答案中
git clone https://github.com/apenwarr/git-subtree.git
cd git-subtree
sudo rsync -a ./git-subtree.sh /usr/local/bin/git-subtree
make doc
make install
# Go into the project root
cd ~/my-project
# Create a branch which only contains commits for the children of 'foo'
git subtree split --prefix=foo --branch=foo-only
# Remove 'foo' from the project
git rm -rf ./foo
# Create a git repo for 'foo' (assuming we already created it on github)
mkdir foo
pushd foo
git init
git remote add origin git@github.com:my-user/new-project.git
git pull ../ foo-only
git push origin -u master
popd
# Add 'foo' as a git submodule to `my-project`
git submodule add git@github.com:my-user/new-project.git foo
# move the folder at prefix to a new branch
git subtree split --prefix=SubFolderName/FolderToBeNewRepo --branch=to-be-new-repo
# create a new repository out of the newly made branch
mkdir ~/Documents/NewRepo
pushd ~/Documents/NewRepo
git init
git pull ~/Documents/OriginalRepo to-be-new-repo
# upload the new repository to a place that should be referenced for submodules
git remote add origin git@github.com:myUsername/newRepo.git
git push -u origin master
popd
# replace the folder with a submodule
git rm -rf ./SubFolderName/FolderToBeNewRepo
git submodule add git@github.com:myUsername/newRepo.git SubFolderName/FolderToBeNewRepo
git branch --delete --force to-be-new-repo
# move the folder at prefix to a new branch
git subtree split --prefix=Assets/SoArchitecture --branch=so-package
# create a new repository out of the newly made branch
mkdir ~/Documents/_Shawn/UnityProjects/SoArchitecture
pushd ~/Documents/_Shawn/UnityProjects/SoArchitecture
git init
git pull ~/Documents/_Shawn/UnityProjects/SoProject so-package
# upload the new repository to a place that should be referenced for submodules
git remote add origin https://github.com/Feddas/SoArchitecture.git
git push -u origin master
popd
# replace the folder with a submodule
git rm -rf ./Assets/SoArchitecture
git submodule add https://github.com/Feddas/SoArchitecture.git
git branch --delete --force so-package