git submodule add -b
如何运作?
添加具有特定分支的子模块后,新的克隆存储库(在git submodule update --init
之后)将处于特定提交,而不是分支本身(子模块上的git status
显示“当前不在任何分支“)。
我找不到.gitmodules
或.git/config
关于子模块的分支或任何特定提交的任何信息,那么Git如何解决这个问题?
另外,是否可以指定标签而不是分支?
我正在使用1.6.5.2版。
答案 0 :(得分:503)
我想在这里添加一个答案,这只是其他答案的集合,但我认为它可能更完整。
当你有这两件事时,你知道你有一个Git子模块。
您的.gitmodules
有一个类似的条目:
[submodule "SubmoduleTestRepo"]
path = SubmoduleTestRepo
url = https://github.com/jzaccone/SubmoduleTestRepo.git
您的Git存储库中有一个子模块对象(在此示例中名为SubmoduleTestRepo)。 GitHub将这些显示为“子模块”对象。或者从命令行执行git submodule status
。 Git子模块对象是特殊类型的Git对象,它们保存特定提交的SHA信息。
无论何时执行git submodule update
,它都会使用提交内容填充子模块。由于.gitmodules
。
现在,-b
所做的只是在.gitmodules
文件中添加一行。所以按照相同的例子,它看起来像这样:
[submodule "SubmoduleTestRepo"]
path = SubmoduleTestRepo
url = https://github.com/jzaccone/SubmoduleTestRepo.git
branch = master
编辑:上面只支持分支名称,而不是SHA或TAG。
子模块对象仍然指向特定的提交。根据Vogella的回答,-b
选项向您购买的唯一内容是能够为您的更新添加--remote
标记:
git submodule update --remote
它不是将子模块的内容填充到子模块指向的提交,而是用主分支上的最新提交替换该提交,然后用该提交填充子模块。这可以通过djacobs7回答分两步完成。由于您现在已经更新了子模块对象所指向的提交,因此您必须将更改的子模块对象提交到Git存储库中。
git submodule add -b
并不是一种神奇的方式来保持一切与分支一致。它只是在.gitmodules
文件中添加有关分支的信息,并为您提供在填充之前将子模块对象更新为指定分支的最新提交的选项。
答案 1 :(得分:278)
(Git 2.22,2019年第二季度,已经引入git submodule set-branch --branch aBranch -- <submodule_path>
)
请注意如果您有一个现有的子模块不跟踪某个分支,那么(if you have git 1.8.2+):
确保父repo知道其子模块现在跟踪分支:
cd /path/to/your/parent/repo
git config -f .gitmodules submodule.<path>.branch <branch>
确保您的子模块实际上是该分支的最新部分:
cd path/to/your/submodule
git checkout -b branch --track origin/branch
# if the master branch already exist:
git branch -u origin/master master
('origin'是 upstream remote repo 的名称,子模块已从中克隆。
该子模块内的git remote -v
将显示它。通常,它是'起源')
不要忘记在父仓库中记录子模块的新状态:
cd /path/to/your/parent/repo
git add path/to/your/submodule
git commit -m "Make submodule tracking a branch"
该子模块的后续更新必须使用--remote
选项:
# update your submodule
# --remote will also fetch and ensure that
# the latest commit from the branch is used
git submodule update --remote
# to avoid fetching use
git submodule update --remote --no-fetch
请注意,使用Git 2.10+(2016年第3季度),您可以使用“.
”作为分支名称:
分支的名称在
submodule.<name>.branch
.gitmodules
中记录为update --remote
。
.
的特殊值用于指示子模块中分支的名称应与当前存储库中当前分支的名称相同。
如果要更新分支后的所有子模块:
git submodule update --recursive --remote
请注意,对于每个更新的子模块,结果几乎总是detached HEAD ,Dan Cameron中的his answer注释。
(Clintm注释in the comments,如果您运行git submodule update --remote
并且生成的sha1与子模块当前所在的分支相同,则它将不执行任何操作并保留子模块仍然“在那个分支上”,而不是处于分离的头状态。)
为了确保分支实际被检出(并且不会修改代表父回购的子模块的 special entry 的SHA1),他建议:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch'
每个子模块仍然会引用相同的SHA1,但如果你做了新的提交,你就可以推送它们,因为它们将被你希望子模块跟踪的分支引用。
在子模块中推送之后,不要忘记返回父级仓库,添加,提交并推送新的SHA1用于那些修改过的子模块。
请注意使用$toplevel
,in the comments推荐Alexander Pogrebnyak
$toplevel
于2010年5月在git1.7.2中引入:commit f030c96。
它包含顶级目录的绝对路径(
.gitmodules
所在的位置。)
foreach脚本无法检出不在分支之后的子模块 但是,此命令可以同时为您提供:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch' –
相同的命令,但更容易阅读:
git submodule foreach -q --recursive \
'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
[ "$branch" = "" ] && \
git checkout master || git checkout $branch' –
umläute使用简化版dtmland优化in the comments命令:
git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
多行:
git submodule foreach -q --recursive \
'git checkout \
$(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
答案 2 :(得分:175)
Git 1.8.2增加了跟踪分支的可能性。
# add submodule to track master branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename
# update your submodule
git submodule update --remote
答案 3 :(得分:50)
我如何使用Git子模块的示例。
看起来有点像这样:
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
也许它有帮助(即使我使用标签而不是分支)?
答案 4 :(得分:36)
根据我的经验,在超级项目或未来结账中切换分支仍会导致子模块的分离HEAD,无论子模块是否被正确添加和跟踪(即@ djacobs7和@Johnny Z答案)。
而不是手动或通过脚本git submodule foreach手动检出正确的分支。
这将检查分支属性的子模块配置文件并检查set分支。
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
答案 5 :(得分:30)
Git子模块有点奇怪 - 它们总是处于“独立头”模式 - 它们不会像你期望的那样更新到分支上的最新提交。
但是,当你考虑它时,这确实有意义。假设我使用子模块 bar 创建存储库 foo 。我推送我的更改并告诉您从存储库 foo 中检出提交a7402be。
然后想象有人在您进行克隆之前,会对存储库 bar 进行更改。
当您从存储库 foo 中签出提交a7402be时,您希望得到我推送的相同代码。这就是为什么子模块在你明确地告诉它们然后进行新的提交之前不会更新的原因。
我个人认为子模块是Git中最令人困惑的部分。有很多地方可以比我更好地解释子模块。我推荐Scott Chacon的Pro Git。
答案 6 :(得分:15)
切换子模块的分支(假设您已经将子模块作为存储库的一部分):
cd
到包含子模块.gitmodules
进行编辑path = ...
和url = ...
下面的branch = your-branch
行;保存文件.gitmodules
。$ git submodule update --remote
...这应该为每个被修改的子模块提取指定分支上的最新提交。
答案 7 :(得分:8)
我的.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-"
答案 8 :(得分:3)
我们使用Quack从另一个Git存储库中提取特定模块。我们需要在没有提供存储库的整个代码库的情况下提取代码 - 我们需要来自该庞大存储库的非常特定的模块/文件,并且每次运行更新时都应该更新。
所以我们以这种方式实现了它:
创建配置
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
它从上面的配置中提取代码。
答案 9 :(得分:1)
为子模块选择分支的唯一效果是,无论何时在--remote
命令行中传递git submodule update
选项,Git都会在分离的HEAD 中签出模式(如果选择了默认的--checkout
行为)所选远程分支的最新提交。
如果使用子模块的浅克隆,那么在使用Git子模块的远程分支跟踪功能时必须特别小心。
您在子模块设置中为此目的选择的分支不是将在git submodule update --remote
期间克隆的分支。
如果您还传递--depth
参数和,则不会指示Git关于您要克隆的分支 - ,实际上您不能1> {{1} } 命令行!! - ,当显式git submodule update
参数缺失时,它将隐式行为git-clone(1)
git clone --single-branch
文档中解释的行为,因此它将仅克隆主分支
毫不奇怪,在--branch
命令执行克隆阶段之后,它最终会尝试检查您之前为子模块设置的远程分支的最新提交,并且,如果这不是主要的,它不是您的本地浅层克隆的一部分,因此它将失败
致命:需要单一修订
无法在子模块路径'mySubmodule'
中找到当前原点/ NotThePrimaryBranch 修订版
答案 10 :(得分:0)
git子模块add -b开发-名称分支名称-https://branch.git