2023年9月2日更新:“正确”的方法是通过git子模块来完成。但是,这需要一些学习和经验。如果急于或只是存档项目,请使用下面的粗暴方法。如果想要学习git子模块以便在git中进行正确的“仓库内部”软件开发,请参阅本答案底部标题为“更多关于git子模块”的部分。
手动、粗暴的方法:
对于任何希望将一堆git仓库存档到一个更大的父仓库中的人来说,最简单的粗暴解决方案就是将所有嵌套的.git文件夹重命名为其他任何名称,例如:.git改为..git。现在,git add -A将像任何其他正常文件夹一样将它们全部添加到父git项目中,您可以轻松地在父仓库中git commit所有内容。完成。
自动、粗暴的方法:
使用git-disable-repos.sh
(
https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles的一部分)。
我在周末刚写了这个脚本,并已经在许多项目中使用过它。它运行得非常好!请查看文件顶部的注释以获取详细信息和安装说明,然后运行
git disable-repos -h
来查看帮助菜单。
安装:
git clone https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles.git
cd eRCaGuy_dotfiles/useful_scripts
mkdir -p ~/bin
ln -si "${PWD}/git-disable-repos.sh" ~/bin/git-disable-repos
. ~/.bashrc
这是标准的使用模式:
cd path/to/parent/repo
git disable-repos --true_dryrun
git disable-repos --true
mv ..git .git
git rm --cached path/to/subrepo
git add -A
git commit
这将提交所有子仓库,包括它们的(现在是..git
).git文件夹和所有git工件,作为普通文件,到父级git仓库中。您有100%的控制权!想要只更新一个子仓库?那么进入该仓库并将其一个..git
文件夹手动重命名为.git
,然后像正常一样使用该子仓库,完成后再次运行git disable-repos --true
(或手动将.git
重新命名为..git
),并将其提交到父仓库中。我的git disable-repos
脚本的美妙之处在于,如果需要的话,它可以快速而无缝地同时禁用或启用数百个子仓库,而手动操作则不切实际。
也许我的用例很奇怪:我需要将大量内容提交到一个仓库中,直到以后能够清理并单独分离出每个子仓库,但它确实满足了我的需求。
以下是git disable-repos -h
的完整帮助菜单输出:
$ git disable-repos -h
'git disable-repos' version 0.3.0
- Rename all ".git" subdirectories in the current directory to "..git" to temporarily
"disable" them so that they can be easily added to a parent git repo as if they weren't
git repos themselves (".git" <--> "..git").
- Why? See my StackOverflow answer here: https://dev59.com/WVYN5IYBdhLWcg3wuaJx#62368415
- See also the "Long Description" below.
- NB: if your sub-repo's dir is already being tracked in your git repo, accidentally, stop
tracking it with this cmd: 'git rm --cached path/to/subrepo' in order to be able to
start tracking it again fully, as a normal directory, after disabling it as a sub-repo
with this script. To view all tracked files in your repo, use 'git ls-files'.
- References:
1. https://dev59.com/pXM_5IYBdhLWcg3wrFMt#1274447
2. https://dev59.com/zYXca4cB1Zd3GeqPPe_j#27416839
3. https://dev59.com/7moy5IYBdhLWcg3wdd1v#14406253
Usage: 'git disable-repos [positional_parameters]'
Positional Parameters:
'-h' OR '-?' = print this help menu, piped to the 'less' page viewer
'-v' OR '--version' = print the author and version
'--true' = Disable all repos by renaming all ".git" subdirectories --> "..git"
So, once you do 'git disable-repos --true' **from within the parent repo's root directory,**
you can then do 'mv ..git .git && git add -A' to re-enable the parent repo ONLY and
stage all files and folders to be added to it. Then, run 'git commit' to commit them.
Prior to running 'git disable-repos --true', git would not have allowed adding all
subdirectories since it won't normally let you add sub-repos to a repo, and it recognizes
sub-repos by the existence of their ".git" directories.
'--true_dryrun' = dry run of the above
'--false' = Re-enable all repos by renaming all "..git" subdirectories --> ".git"
'--false_dryrun' = dry run of the above
'--list' = list all ".git" and "..git" subdirectories
Common Usage Examples:
1. To rename all '.git' subdirectories to '..git' **except for** the one immediately in the current
directory, so as to not disable the parent repo's .git dir (assuming you are in the parent
repo's root dir when running this command), run this:
git disable-repos --true # disable all git repos in this dir and below
mv ..git .git # re-enable just the parent repo
Be sure to do a dry run first for safety, to ensure it will do what you expect:
git disable-repos --true_dryrun
2. To recursively list all git repos within a given folder, run this command from within the
folder of interest:
git disable-repos --list
3. Assuming you tried to add a sub-repo to your main git repo previously, BEFORE you deleted or
renamed the sub-repo's .git dir to disable the sub-repo, this is the process to disable
the sub-repo, remove it from your main repo's tracking index, and now re-add it to your
main repo as a regular directory, including all of its sub-files and things:
Description: remove sub-repo as a sub-repo, add it as a normal directory, and commit
all of its files to your main repo:
Minimum Set of Commands (just gets the job done without printing extra info.):
git disable-repos --true # disable all repos in this dir and below
mv ..git .git # re-enable just the main repo
# quit tracking the subrepo as a single file
git rm --cached path/to/subrepo
# start tracking the subrepo as a normal folder
git add -A
git commit
Full Set of Commands (let's you see more info. during the process):
git disable-repos --true # disable all repos in this dir and below
mv ..git .git # re-enable just the main repo
git ls-files path/to/subrepo # see what is currently tracked in the subrepo dir
# quit tracking the subrepo as a single file
git rm --cached path/to/subrepo
git status
# start tracking the subrepo as a normal folder
git add -A
git status
git commit
Long Description:
I want to archive a bunch of small git repos inside a single, larger repo, which I will back up on
GitHub until I have time to manually pull out each small, nested repo into its own stand-alone
GitHub repo. To do this, however, 'git' in the outer, parent repo must NOT KNOW that the inner
git repos are git repos! The easiest way to do this is to just rename all inner, nested '.git'
folders to anything else, such as to '..git', so that git won't recognize them as stand-alone
repositories, and so that it will just treat their contents like any other normal directory
and allow you to back it all up! Thus, this project is born. It will allow you to quickly
toggle the naming of any folder from '.git' to '..git', or vice versa. Hence the name of this
project: git-disable-repos.
See my answer here:
https://dev59.com/WVYN5IYBdhLWcg3wuaJx#62368415
This program is part of: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
其他更复杂的工具:
对于寻求更“专业”解决方案的人来说,以下是最受欢迎的解决方案,按照最受欢迎(似乎也是最受支持?)的顺序排列:
git submodule
- https://git-scm.com/docs/git-submodule - 这是内置在 git
中的官方支持工具。
git subtree
- https://www.atlassian.com/git/tutorials/git-subtree
git subrepo
- https://github.com/ingydotnet/git-subrepo
哪个是最好的?我无法说,但它们对我来说都很令人困惑,所以在这种情况下,我选择了上面描述的手动、蛮力选项,因为这样最符合我的预期目的,直到有一天我能找到时间将每个子仓库拆分成自己单独维护的仓库放在GitHub上。
关于 git submodule
的更多信息:
2023年9月2日更新:我现在已经使用了几年的git submodule
。要了解基本命令和其他内容,请参阅我在eRCaGuy_dotfiles repo here中标题为"Git submodules and Git LFS: how to clone this repo and all git submodules and git lfs files"的部分。(另外,不要使用git lfs
。请参阅我的question here和answer here,两者都包含了解释和原因。)
2020年9月21日更新:马丁·欧文(Martin Owen)在2016年5月的一篇文章(
"Git Submodules vs Git Subtrees")中对
git submodule
和
git subtree
进行了很好的比较,并普遍偏向于
git submodule
。然而,当时作者甚至不知道
git subrepo
的存在,并且除了在评论中提到它时没有提及。
git submodule
似乎是内置在
git
中的官方支持工具。虽然它看起来确实有一定的学习曲线,但我计划在我的下一个项目中使用它,现在我准备开放该项目并开始工作,而且它依赖于子git仓库。我打算从这里开始学习它:
Atlassian's Bitbucket提供了一个简短的介绍:
https://www.atlassian.com/git/tutorials/git-submodule
这里是官方的
git submodule
文档:
https://git-scm.com/book/en/v2/Git-Tools-Submodules
另外,你还可以参考以下内容:
1. 我在
如何更新存储库中的所有git子模块(两种方法实现两个非常不同的功能!)上的回答。
附加参考资料:
- https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec
- 何时使用git subtree?
- https://webmasters.stackexchange.com/questions/84378/how-can-i-create-a-git-repo-that-contains-several-other-git-repos
- Git如何将嵌套的git仓库视为普通文件/文件夹处理?
- Git:如何使外部仓库和嵌入式仓库作为常规/独立的仓库工作?
- https://www.atlassian.com/git/tutorials/git-subtree
关键词:git添加子仓库;git添加子目录;git添加嵌套仓库;git添加.git文件夹和文件