git子模块add -b如何工作?
在添加带有特定分支的子模块后,一个新的克隆存储库(在git子模块update——init之后)将在特定的提交处,而不是分支本身(子模块上的git状态显示为“not current on any branch”)。
我在.gitmodules或.git/config中找不到任何关于子模块分支或任何特定提交的信息,那么Git是如何解决的呢?
另外,是否可以指定一个标记而不是分支?
我使用的是1.6.5.2版本。
git子模块add -b如何工作?
在添加带有特定分支的子模块后,一个新的克隆存储库(在git子模块update——init之后)将在特定的提交处,而不是分支本身(子模块上的git状态显示为“not current on any branch”)。
我在.gitmodules或.git/config中找不到任何关于子模块分支或任何特定提交的信息,那么Git是如何解决的呢?
另外,是否可以指定一个标记而不是分支?
我使用的是1.6.5.2版本。
Git子模块有点奇怪——它们总是处于“分离头”模式——它们不会像你期望的那样更新到分支上的最新提交。
不过,当你仔细思考时,这确实是有道理的。假设我用子模块bar创建了存储库foo。我推送我的更改并告诉您从存储库foo中提交a7402be。
然后想象一下,在您可以克隆之前,有人将更改提交到存储库栏。
当您从存储库foo签出commit a7402be时,您希望得到与我推送的相同的代码。这就是为什么子模块不会更新,直到你显式地告诉它们,然后进行新的提交。
我个人认为子模块是Git中最令人困惑的部分。有很多地方可以比我更好地解释子模块。我推荐Scott Chacon的Pro Git。
注意:Git 1.8.2增加了跟踪分支的可能性。下面是一些答案。
习惯这一点有点令人困惑,但子模块并不在分支上。正如您所说,它们只是指向子模块存储库的特定提交的指针。
这意味着,当其他人签出你的存储库,或提取你的代码,并进行git子模块更新时,子模块将被签出到特定的提交。
这对于不经常更改的子模块非常有用,因为这样项目中的每个人都可以在同一次提交时拥有子模块。
如果你想移动子模块到一个特定的标签:
cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push
然后,另一个希望将submodule_directory更改为该标记的开发人员执行此操作
git pull
git submodule update --init
Git拉修改提交他们的子模块目录指向。Git子模块update实际上合并到新代码中。
一个我如何使用Git子模块的例子。
创建一个新的存储库 然后将另一个存储库克隆为子模块 然后让该子模块使用一个名为V3.1.2的标记 然后我们承诺。
它看起来有点像这样:
git init
vi README
git add README
git commit
git submodule add git://github.com/XXXXX/xxx.yyyy.git stm32_std_lib
git status
git submodule init
git submodule update
cd stm32_std_lib/
git reset --hard V3.1.2
cd ..
git commit -a
git submodule status
也许它有帮助(即使我使用标记而不是分支)?
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子模块。
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.
(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调用它。
根据我的经验,在超级项目或未来的签出中切换分支仍然会导致子模块的头部分离,无论子模块是否正确添加和跟踪(即@djacobs7和@Johnny Z答案)。
而不是手动签出正确的分支手动或通过脚本git子模块foreach可以使用。
这将检查子模块配置文件中的分支属性并检出set分支。
Git子模块foreach -q——recursive 'branch="$(Git config -f $ topllevel . "gitmodules子模块。name.branch美元)”;Git checkout $branch'
我的.gitconfig文件中有这个。它仍然是一份草案,但目前证明是有用的。它帮助我总是将子模块重新连接到它们的分支。
[alias]
######################
#
# Submodules aliases
#
######################
# git sm-trackbranch: places all submodules on their respective branch specified in .gitmodules
# This works if submodules are configured to track a branch, i.e if .gitmodules looks like:
# [submodule "my-submodule"]
# path = my-submodule
# url = git@wherever.you.like/my-submodule.git
# branch = my-branch
sm-trackbranch = "! git submodule foreach -q --recursive 'branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; git checkout $branch'"
# sm-pullrebase:
# - pull --rebase on the master repo
# - sm-trackbranch on every submodule
# - pull --rebase on each submodule
#
# Important note:
# - have a clean master repo and subrepos before doing this!
# - this is *not* equivalent to getting the last committed
# master repo + its submodules: if some submodules are tracking branches
# that have evolved since the last commit in the master repo,
# they will be using those more recent commits!
#
# (Note: On the contrary, git submodule update will stick
# to the last committed SHA1 in the master repo)
sm-pullrebase = "! git pull --rebase; git submodule update; git sm-trackbranch ; git submodule foreach 'git pull --rebase' "
# git sm-diff will diff the master repo *and* its submodules
sm-diff = "! git diff && git submodule foreach 'git diff' "
# git sm-push will ask to push also submodules
sm-push = push --recurse-submodules=on-demand
# git alias: list all aliases
# useful in order to learn git syntax
alias = "!git config -l | grep alias | cut -c 7-"
我们使用Quack从另一个Git存储库中提取特定的模块。我们需要在不使用所提供的存储库的整个代码库的情况下提取代码——我们需要从庞大的存储库中获得一个非常特定的模块/文件,并且应该在每次运行update时进行更新。
所以我们是这样实现的:
创建配置
name: Project Name
modules:
local/path:
repository: https://github.com/<username>/<repo>.git
path: repo/path
branch: dev
other/local/path/filename.txt:
repository: https://github.com/<username>/<repo>.git
hexsha: 9e3e9642cfea36f4ae216d27df100134920143b9
path: repo/path/filename.txt
profiles:
init:
tasks: ['modules']
通过上述配置,它从第一个模块配置中指定的提供的GitHub存储库创建了一个目录,而另一个目录是从给定的存储库中提取并创建一个文件。
其他开发人员只需要运行
$ quack
它从上面的配置中提取代码。
为了切换子模块的分支(假设你已经将子模块作为存储库的一部分):
CD到包含子模块的存储库的根目录 打开.gitmodules进行编辑 在path =…url =…对于每个子模块,它说branch = your-branch;保存文件。gitmodules。 然后在不改变目录的情况下执行$ git子模块update——remote
...对于这样修改的每个子模块,这应该拉入指定分支上的最新提交。
为子模块选择分支的唯一效果是,每当你在git子模块更新命令行中传递——remote选项时,git将以分离HEAD模式(如果选择默认的——checkout行为)检出所选远程分支的最新提交。
You must be particularly careful when using this remote branch tracking feature for Git submodules if you work with shallow clones of submodules. The branch you choose for this purpose in submodule settings IS NOT the one that will be cloned during git submodule update --remote. If you pass also the --depth parameter and you do not instruct Git about which branch you want to clone -- and actually you cannot in the git submodule update command line!! -- , it will implicitly behave like explained in the git-clone(1) documentation for git clone --single-branch when the explicit --branch parameter is missing, and therefore it will clone the primary branch only.
毫无疑问,在git子模块update命令执行克隆阶段之后,它最终将尝试检出之前为子模块设置的远程分支的最新提交,如果这不是主分支,那么它就不是本地浅克隆的一部分,因此它将失败
致命的:需要一次修改 无法在子模块路径“mySubmodule”中找到当前的origin/NotThePrimaryBranch修订
现有的答案忽略了第二步,并且有过多的细节。
切换一个现有的子模块来跟踪一个新的远程url和/或一个新的分支:
在.gitmodules中编辑真相的来源。
例如,从
[submodule "api"]
path = api
url = https://github.com/<original_repo>/api.git
to
[submodule "api"]
path = api
url = https://github.com/<another_repo>/api.git
branch = work-in-progress
你也可以使用hexsha来进行提交哈希。或标签,但见3。
git子模块同步:从.gitmodules中指定的刚刚编辑过的真值源中更新git在.git/modules中缓存的子模块的描述。 只有当你指定一个标签:git submodule foreach——recursive 'git fetch——tags'来获取标签。 git子模块update——init——recursive——remote:更新工作副本中签出的子模块。 提交更改。
使用下面的命令
添加子模块(分支-分支)
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
在提交和推送相应的.. 现在子模块将得到更新。