如何使外部存储库和嵌入式存储库作为通用/独立存储库工作?

时间:2017-10-30 04:49:30

标签: git github version-control

我有一个大项目(比方说A repo),它有一个来自B repo的子文件夹。当我从A repo

提交时,我会收到如下警告
warning: adding embedded git repository: extractor/annotator-server
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint:
hint:   git submodule add <url> extractor/annotator-server
hint:
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint:
hint:   git rm --cached extractor/annotator-server
hint:
hint: See "git help submodule" for more information.

我看过git-submodulegit-subtree

Maintaining Git repo inside another git repo

https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree

但我不喜欢它们,因为它们需要额外的配置。

我想要的是,例如:

结构如:

A/
--- a.py

--- B/
--- B/b.py

当我更改B/b.py时。

  1. 如果我在路径A/上,git add可以检测到B/b.py已更改,git push只会将其提交给A repo。

    git add .   (would add changes under A/  )
    git push   (would push changes under A/  )
    git pull   (would pull changes under A/  )
    git clone XXX:A  (would clone all files under A/ ,    A/B/ is just looks like plain folder with all files, not a repo )
    
  2. 如果我在路径A/B/上,git add只会将B/b.py更改添加到B repo,而git push只会将其提交给B repo。

    git add .   (would add changes under B/ , but not add changes to A repo)
    git push   (would push changes under B/ , but not push changes to A repo)
    git pull   (would clone changes under B/ ,  )
    git clone XXX:B  (would clone all files under B/  )
    
  3. 一旦我想在另一台机器上使用A和B,只需执行

    git clone A
    rm -rf A/B/
    git clone B ./B
    git add . && git commit 'sync with B'
    
  4. 换句话说,A和B充当独立的回购。

    但事实是,A repo将B repo视为子模块:

    回购 https://github.com/eromoe/test

    B回购 https://github.com/eromoe/test2

    如何强制A repo跟踪A/下的所有文件,B repo跟踪A/B/下的所有文件?我希望A和B充当自包含的回购,没有任何其他配置。

6 个答案:

答案 0 :(得分:8)

您可以使用以下命令将test2 repo中的文件添加到test repo中,如下所示:

# In local test repo
rm -rf test2
git clone https://github.com/eromoe/test2
git add test2/
git commit -am 'add files from test2 repo to test repo'
git push

注意:

您应该使用 git add test2/ (使用斜杠,而不是git add test2)。

git add test2/会将test2个文件夹及其文件视为普通文件夹和测试仓库文件(创建模式100644)。

git add test2会将test2文件夹视为测试仓库的子模块(创建模式160000)。

答案 1 :(得分:6)

可能是git提醒了存储库。它对我有帮助:

    git rm --cached your_folder_with_repo
    git commit -m "remove cached repo"
    git add your_folder_with_repo/
    git commit -m "Add folder"
    git push

答案 2 :(得分:3)

手动暴力破解方法:

对于登陆此页面的目的仅是将一堆git repos存档在更大的父repo或其他东西中的人,最简单的暴力解决方案是将所有嵌套的.git文件夹重命名为其他任何内容- -ex:到..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
# If this is the first time using your ~/bin dir, log out and
# log back in now. Otherwise, just re-source your .bashrc file:
. ~/.bashrc

这是标准用法模式:

cd path/to/parent/repo
# Do a dry-run to see which repos will be temporarily disabled
git disable-repos --true_dryrun
# Now actually disable them: disable all git repos in this dir and below
git disable-repos --true
# re-enable just the parent repo
mv ..git .git
# quit tracking the subrepo as a single file (required
# if you previously tried to add it to your main repo before
# disabling it as a git repo)
git rm --cached path/to/subrepo
# add all files, including the now-disabled sub-repos, to the parent repo
git add -A
# commit all files
git commit

这会将所有子存储库(包括其(现在为..git)。git文件夹和所有git工件(作为常规文件)提交给父git repo。您拥有100%的控制权!是否只想更新1个子仓库?然后将其插入cd,然后手动将其..git文件夹重命名为.git,然后像往常一样使用该子存储库,然后在其上再次运行git disable-repos --true(或手动执行从.git重命名为..git),然后将其提交到父仓库中。我的git disable-repos脚本的优点在于,如果有必要,它可以一次快速,几乎没有效果地禁用或启用100个子存储库,而手动进行则不切实际。

也许我的用例很奇怪:我只需要将大量的东西提交到一个仓库中,直到以后我可以清理并分离出每个子仓库,但这确实是我需要做的。 / p>

这是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://stackoverflow.com/a/62368415/4561887
  - 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://stackoverflow.com/questions/1274057/how-to-make-git-forget-about-a-file-that-was-tracked-but-is-now-in-gitignore/1274447#1274447
        2. https://stackoverflow.com/questions/27403278/add-subproject-as-usual-folder-to-repository/27416839#27416839
        3. https://stackoverflow.com/questions/8533202/list-files-in-local-git-repo/14406253#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://stackoverflow.com/questions/47008290/how-to-make-outer-repository-and-embedded-repository-work-as-common-standalone-r/62368415#62368415

This program is part of: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles

其他工具:

对于任何寻求更“专业”解决方案的人来说,这些似乎是最受欢迎的解决方案,首先是最受欢迎的(因此似乎是最受支持的?):

  1. git submodule-https://git-scm.com/docs/git-submodule
  2. git subtree-https://www.atlassian.com/git/tutorials/git-subtree
  3. git subrepo-https://github.com/ingydotnet/git-subrepo

其中哪些是最好的?我不能说,但是它们都让我感到困惑,所以我选择了上面描述的手动蛮力选项,因为在这种情况下,这最符合我的预期目的,直到我找到时间分解每个子组件为止。 -repos有一天会在GitHub上保存到自己的个人维护仓库中。

有关git submodule的更多信息:

更新2020年9月21日::马丁·欧文(Martin Owen)在2016年5月发表的文章("Git Submodules vs Git Subtrees")对git submodulegit subtree进行了很好的比较,通常偏爱git submodule。但是,作者当时甚至还没有意识到git subrepo,除了在评论中提到它外,没有提及它。

git submodule似乎是git中内置的规范的,官方支持的工具。尽管看起来它确实具有学习曲线,但是我准备在下一个项目中使用它,因为我已经准备好打开该项目并重新开始它,并且它取决于sub-git repos。我打算从这里开始学习:

  1. Atlassian的Bitbucket的简短介绍:https://www.atlassian.com/git/tutorials/git-submodule
  2. git submodule官方文档在这里:https://git-scm.com/book/en/v2/Git-Tools-Submodules

其他参考文献:

  1. https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec
  2. When to use git subtree?
  3. https://webmasters.stackexchange.com/questions/84378/how-can-i-create-a-git-repo-that-contains-several-other-git-repos
  4. Git treat nested git repos as regular file/folders
  5. How to make outer repository and embedded repository work as common/standalone repository?
  6. https://www.atlassian.com/git/tutorials/git-subtree

答案 3 :(得分:1)

如果您不关心B A正在使用的确切版本,您可以保留当前设置(嵌套git repos)。

您将拥有&#34;嵌入式回购&#34;警告,但除此之外,两个回购将按照您的预期行事,每个回购添加,提交和仅推送他们的回购。
注意:您可以使用git config advice.addEmbeddedRepo

将该警告缩短/清空

答案 4 :(得分:0)

要详细介绍rost shan's answer

在Ubuntu 20.04上使用Rails应用程序时遇到此问题。

运行命令git add .时收到错误消息:

hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint: 
hint:   git submodule add <url> letsencrypt_cred
hint: 
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint: 
hint:   git rm --cached letsencrypt_cred
hint: 
hint: See "git help submodule" for more information.

这是我修复的方式

从git撤消所有已暂存的文件,以供我尝试推送至的存储库:

git rm --cached letsencrypt_cred

OR

git rm -f --cached letsencrypt_cred (to force removal)

提交当前目录中所有的文件:

git commit -m "modify credentials"

添加要推送到的远程存储库:

git remote add origin https://github.com/promisepreston/letsencrypt_cred.git

将文件推送到远程存储库

git push -u origin main

OR

git push -u origin master

仅此而已。

我希望这会有所帮助

答案 5 :(得分:0)

我删除了该特定文件夹中的.git。然后我运行了命令

git add folder_which_has_deleted_dot_git
git commit -m "Changed to standalone repo"

然后,我能够跟踪该文件夹并将其转换为通用/独立存储库。