Answers:
注意: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 pull
提交其子模块目录指向的更改。 git submodule update
实际上合并到新代码中。
cd my_submodule; git checkout [ref in submodule's repository
产量fatal: reference is not a tree: ...
。好像git
只能在父存储库上运行。
git checkout v1.0
分支还是标签?
我想在这里添加一个答案,它实际上只是其他答案的集合,但我认为它可能会更完整。
当您拥有这两件事时,您就知道您拥有一个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
注意:文件中仅支持分支名称
.gitmodules
,但不支持SHA和TAG!(相反,可以使用“git add .
” 来跟踪和更新每个模块的分支提交,例如likegit add ./SubmoduleTestRepo
,并且您不必.gitmodules
每次都更改文件)
子模块对象仍指向特定的提交。该-b
选件可以为--remote
您提供的唯一好处是可以根据Vogella的答案在更新中添加标志:
git submodule update --remote
与其将子模块的内容填充到子模块所指向的提交中,它不使用在master分支上的最新提交来替换该提交,然后使用该提交来填充子模块。这可以通过djacobs7答案分两步完成。由于现在已经更新了子模块对象指向的提交,因此必须将更改后的子模块对象提交到Git存储库中。
git submodule add -b
这不是使分支保持最新状态的一种神奇方法。它只是在.gitmodules
文件中添加有关分支的信息,并为您提供在填充子模块对象之前将其更新为指定分支的最新提交的选项。
.gitmodules
,执行完后出现$ git submodule update --init --remote TestModule
了一个错误,说fatal: Needed a single revision
和Unable to find current origin/TestTag revision in submodule path 'TestModule'
。在使用真实分支时,它可以工作。无论如何,.gitmodules
无需指定确切的提交就可以指定标签?
.gitmodules
并运行git submodule update
,什么都没有发生?
(Git 2.22,Q2 2019,已引入git submodule set-branch --branch aBranch -- <submodule_path>
)
请注意,如果您有一个尚未跟踪分支的现有子模块,则(如果您有git 1.8.2+):
确保父仓库知道其子模块现在跟踪分支:
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”是从其克隆了子模块的上游远程回购的名称。
甲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年第三季度)中,您可以使用' .
'作为分支名称:
分支的名称记录
submodule.<name>.branch
在.gitmodules
了update --remote
。
的特殊价值.
用来指示子模块中分支的名称应与当前存储库中的当前分支的名称相同。
使用
git checkout
,如果要跟随的分支名称是“.
”,它将杀死您的未提交工作!
采用git switch
代替。
这意味着Git 2.23(2019年8月)或更高版本。
参见“ 混淆者git checkout
”
如果要在分支之后更新所有子模块:
git submodule update --recursive --remote
请注意,对于每个更新的子模块,结果几乎都将是独立的HEAD,如Dan Cameron在其答案中所述。
(克林特姆在评论中指出是,如果你运行git submodule update --remote
所得SHA1是一样的分支目前的子模块上,它不会“对分支”做任何事情,离开子模块仍而不是分离的头的状态。 )
为了确保实际检出分支(不会修改代表父仓库的子模块的特殊条目的SHA1 ),他建议:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'
每个子模块仍将引用相同的SHA1,但是如果您进行新的提交,则可以推送它们,因为它们将由您希望子模块跟踪的分支引用。
在子模块中进行推送之后,不要忘记返回到父仓库,为那些修改后的子模块添加,提交并推送新的SHA1。
使用注意事项$toplevel
,建议在评论由亚历山大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 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()提交的0222540(2020年1月16日)。(由Junio C Hamano合并--在commit b5c71cc中,2020年2月5日)nasamuffin
gitster
fetch
:强调子模块获取期间的失败签名人:艾米莉·谢弗(Emily Shaffer)
如果在子模块存在多个子模块的情况下子模块获取失败,则如果失败的原因多于一个,则来自唯一失败子模块获取的错误将隐藏在其他子模块的活动中
fetch-by-oid
。
尽早排除故障,以便用户知道出了点问题以及在哪里。因为
fetch_finish()
只run_processes_parallel,
需要通过静音同步调用即可,因此不需要submodules_with_errors
。
foreach
脚本将不依赖于硬编码<path>
,如果你替换<path>
用$toplevel/
。
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 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
git submodule update --remote --merge
或来执行子模块更新git submodule update --remote --rebase
。这些命令跟踪远程分支。
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
另请参阅Git子模块
.gitmodules
文件上?
git submodule add -b tags/<sometag> <url>
您可以为线看到branch = tags/<sometag>
的.gitmodules
我如何使用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
也许有帮助(即使我使用标签而不是分支)?
git reset --hard V3.1.2
吗?我只得到git status
父目录的“无可奉告” 。
以我的经验,无论是否正确添加和跟踪了子模块(即@ djacobs7和@Johnny Z的答案),在超级项目中切换分支或将来的结帐仍会导致子模块的HEAD分离。
代替手动或通过脚本git子模块foreach手动签出正确的分支。
这将检查子模块配置文件中的branch属性,并检出set分支。
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
Git子模块有点奇怪-它们始终处于“分离头”模式-它们不会像您期望的那样更新到分支上的最新提交。
但是,当您考虑时,这确实有意义。假设我使用子模块bar创建存储库foo。我推送更改,并告诉您从存储库foo中检出commit a7402be 。
然后,假设有人对存储库栏进行了更改,然后再进行克隆。
当您从存储库foo中提交a7402be时,您期望得到与我推送的相同的代码。这就是为什么直到您明确告诉子模块然后进行新提交才更新子模块的原因。
我个人认为子模块是Git最令人困惑的部分。有很多地方可以比我更好地解释子模块。我推荐Scott Chacon的Pro Git。
git clone git://github.com/git/git.git
并推动该功能...?= D
我的.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
并且它从上述配置中提取代码。
为子模块选择分支的唯一效果是,每当您--remote
在git submodule update
命令行中传递该选项时,Git都会以分离的HEAD模式(如果--checkout
选择了默认行为)签出该选定远程分支的最新提交。
如果使用子模块的浅表克隆,则在对Git子模块使用此远程分支跟踪功能时必须特别小心。您在子模块设置中为此选择的分支不是将在期间克隆的分支git submodule update --remote
。如果您还传递了--depth
参数,但是您没有指示Git您要克隆哪个分支 - 实际上您不能在git submodule update
命令行中使用!-时,它会隐含地像git-clone(1)
文档中说明的那样在缺少git clone --single-branch
显式--branch
参数时起作用,因此它将仅克隆主分支。
毫不奇怪,在git submodule update
命令执行克隆阶段之后,它最终将尝试检出您先前为子模块设置的远程分支的最新提交,并且,如果不是主要分支,则不属于该分支您的本地浅表克隆,因此将失败
致命:需要进行一次修订
在子模块路径“ mySubmodule”中找不到当前源/ NotThePrimaryBranch修订版
git子模块添加-b开发-名称分支名称-https://branch.git