git子模块add -b如何工作?

在添加带有特定分支的子模块后,一个新的克隆存储库(在git子模块update——init之后)将在特定的提交处,而不是分支本身(子模块上的git状态显示为“not current on any branch”)。

我在.gitmodules或.git/config中找不到任何关于子模块分支或任何特定提交的信息,那么Git是如何解决的呢?

另外,是否可以指定一个标记而不是分支?

我使用的是1.6.5.2版本。


当前回答

我想在这里补充一个答案,它实际上只是其他答案的综合,但我认为它可能更完整。

有了这两个东西,就有了Git子模块。

Your .gitmodules has an entry like so: [submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git You have a submodule object (named SubmoduleTestRepo in this example) in your Git repository. GitHub shows these as "submodule" objects. Or do git submodule status from a command line. Git submodule objects are special kinds of Git objects, and they hold the SHA information for a specific commit. Whenever you do a git submodule update, it will populate your submodule with content from the commit. It knows where to find the commit because of the information in the .gitmodules. Now, all the -b does is add one line in your .gitmodules file. So following the same example, it would look like this: [submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git branch = master Note: only branch name is supported in a .gitmodules file, but SHA and TAG are not supported! (instead of that, the branch's commit of each module can be tracked and updated using "git add .", for example like git add ./SubmoduleTestRepo, and you do not need to change the .gitmodules file each time) The submodule object is still pointing at a specific commit. The only thing that the -b option buys you is the ability to add a --remote flag to your update as per Vogella's answer: git submodule update --remote Instead of populating the content of the submodule to the commit pointed to by the submodule, it replaces that commit with the latest commit on the master branch, THEN it populates the submodule with that commit. This can be done in two steps by djacobs7 answer. Since you have now updated the commit the submodule object is pointing to, you have to commit the changed submodule object into your Git repository. git submodule add -b is not some magically way to keep everything up to date with a branch. It is simply adds information about a branch in the .gitmodules file and gives you the option to update the submodule object to the latest commit of a specified branch before populating it.

其他回答

为了切换子模块的分支(假设你已经将子模块作为存储库的一部分):

CD到包含子模块的存储库的根目录 打开.gitmodules进行编辑 在path =…url =…对于每个子模块,它说branch = your-branch;保存文件。gitmodules。 然后在不改变目录的情况下执行$ git子模块update——remote

...对于这样修改的每个子模块,这应该拉入指定分支上的最新提交。

Git 1.8.2增加了跟踪分支的可能性。

# add submodule to track branch_name branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

参见Git子模块

(Git 2.22, Q2 2019,引入了Git子模块set-branch——branch branch——<submodule_path>)

注意,如果你有一个现有的子模块,它还没有跟踪分支,那么(如果你有git 1.8.2+):

确保父repo知道它的子模块现在跟踪一个分支: cd /道路/ /你/父母/回购 Git config -f . Git modules submodule.<path>。分支<分支> 确保你的子模块实际上位于该分支的最新位置: cd路径/ /你/子模块 Git checkout -b branch——跟踪原点/分支 #如果主分支已经存在: Git branch -u origin/master master

         (其中'origin'是子模块克隆的上游远程repo的名称。          该子模块中的git remote -v将显示它。通常是“origin”)

不要忘记在父repo中记录子模块的新状态: cd /道路/ /你/父母/回购 Git添加路径/到/your/子模块 让子模块跟踪一个分支 该子模块的后续更新必须使用——remote选项: #更新子模块 #——remote也将获取并确保 #使用来自分支的最新提交 Git子模块update——remote #来避免抓取使用 Git子模块更新——remote——no-fetch


注意,在Git 2.10+(2016年Q3)中,您可以使用'。'作为分支名称:

分支的名称被记录为submodule.<name>。在.gitmodules中分支update——remote。 的特殊值用于指示子模块中的分支名称应与当前存储库中的当前分支名称相同。

但是,正如LubosD所评论的那样

使用git签出,如果分支名称是“。”,它将终止您未提交的工作! 使用git switch代替。

这意味着Git 2.23(2019年8月)或更高版本。

参见“git checkout让人困惑”


如果你想更新分支后面的所有子模块:

    git submodule update --recursive --remote

注意,对于每个更新的子模块,结果几乎总是一个分离的HEAD,正如Dan Cameron在他的回答中指出的那样。

(Clintm在评论中指出,如果你运行git子模块update -remote,结果sha1与子模块当前所在的分支相同,它将不会做任何事情,并让子模块仍然“在该分支上”,而不是处于分离头状态。)

为了确保分支被实际签出(这不会修改代表父repo子模块的特殊条目的SHA1),他建议:

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'

每个子模块仍然会引用相同的SHA1,但是如果你做了新的提交,你将能够推送它们,因为它们将被你希望子模块跟踪的分支引用。 在子模块内的推送之后,不要忘记返回父repo,为那些修改后的子模块添加、提交和推送新的SHA1。

注意使用$ topllevel,这是Alexander Pogrebnyak在评论中推荐的。 $ topllevel于2010年5月在git1.7.2中引入:commit f030c96。

它包含顶级目录(.gitmodules所在目录)的绝对路径。

Dtmland在评论中补充道:

foreach脚本将无法签出不遵循分支的子模块。 然而,这个命令会给你两个:

 git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git switch $branch' –

同样的命令,但更容易阅读:

git submodule foreach -q --recursive \
    'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
     [ "$branch" = "" ] && \
     git checkout master || git switch $branch' –
  

Umläute在评论中提炼了dtmland命令的简化版本:

git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

多行:

git submodule foreach -q --recursive \
  'git switch \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

在Git 2.26 (Q1 2020)之前,在子模块中递归地获取更新不可避免地会产生大量的输出,并且很难发现错误消息。

该命令已被教导枚举在操作结束时出现错误的子模块。

参见Emily Shaffer (nasamuffin)提交的0222540(2020年1月16日)。 (由Junio C Hamano—gitster—在commit b5c71cc中合并,2020年2月5日)

获取:强调子模块获取失败 署名:Emily Shaffer

在有很多子模块的情况下,当一个子模块读取失败时,如果多个读取返回到按oid读取,那么来自唯一失败的子模块读取的错误将被隐藏在其他子模块的活动之下。 延迟调用故障,这样用户就能意识到哪里出了问题。

因为fetch_finish()只由run_processes_parallel同步调用,所以在submodules_with_errors周围不需要互斥。


注意,在Git 2.28 (Q3 2020)中,继续重写脚本化的“Git子模块”Porcelain命令的部分内容;这次轮到“git submodule set-branch”子命令了。

参见Shourya Shukla (periperidip)提交2964d6e (02 Jun 2020)。 (由Junio C Hamano—gitster—在commit 1046282中合并,2020年6月25日)

子模块:端口子命令'set-branch'从shell到C 导师:Christian Couder 导师:karartic Sivaraam 帮助:Denton Liu 资助人:Eric Sunshine 帮助:Đoàn trn Công Danh 署名:Shourya Shukla

将子模块子命令“set-branch”转换为内置命令,并通过git submodule.sh调用它。

使用下面的命令

添加子模块(分支-分支)

git submodule add -b stage git@github.optum.com:orgname/${reponame}.git

更新子模块(分支-分支)

######Clone########

> git clone -b master --single-branch --recurse-submodules git@github.com:orgname/project.git  
or  
> git clone -b stage --single-branch --recurse-submodules git@github.com:orgname/project.git

######Update#######
> git submodule update  --remote (only for remote branch -ie master) 
or 
> git submodule update --recursive --remote

> git submodule update --init --recursive (for remaining branchs)

if you get fatal need single revision error then use below commands:-

before:-

*** stage
  remotes/origin/stage**

git branch -a

git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/{branch name}
ex:- git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/stage

after:-
*** stage
  remotes/origin/HEAD -> origin/stage
  remotes/origin/stage**

then 

> git reset --hard

#hard reset revisions#

> git submodule foreach git reset --hard origin/develop

> git submodule foreach git pull origin develop

在提交和推送相应的.. 现在子模块将得到更新。

根据我的经验,在超级项目或未来的签出中切换分支仍然会导致子模块的头部分离,无论子模块是否正确添加和跟踪(即@djacobs7和@Johnny Z答案)。

而不是手动签出正确的分支手动或通过脚本git子模块foreach可以使用。

这将检查子模块配置文件中的分支属性并检出set分支。

Git子模块foreach -q——recursive 'branch="$(Git config -f $ topllevel . "gitmodules子模块。name.branch美元)”;Git checkout $branch'