How can I specify a branch/tag when adding a Git submodule?
在添加具有特定分支的子模块后,新的克隆存储库(在
我找不到关于该子模块分支或任何特定提交的
另外,是否可以指定标记而不是分支?
我使用的是1.6.5.2版。
注:Git 1.8.2增加了跟踪分支的可能性。请看下面的一些答案。
习惯这个有点让人困惑,但是子模块不在分支上。正如您所说,它们只是指向子模块存储库特定提交的一个指针。
这意味着,当其他人签出您的存储库,或者提取您的代码,并且执行git子模块更新时,子模块将签出到特定的提交中。
对于不经常更改的子模块来说,这是很好的,因为这样项目中的每个人都可以在同一提交中拥有子模块。
如果要将子模块移动到特定的标记:
1 2 3 4 5 6 | cd submodule_directory git checkout v1.0 cd .. git add submodule_directory git commit -m"moved submodule to v1.0" git push |
然后,另一个想要将子模块目录更改为该标记的开发人员,是这样做的吗?
1 2 | git pull git submodule update |
我想在这里添加一个答案,它实际上只是其他答案的组合,但我认为它可能更完整。
当你有这两样东西的时候,你知道你有一个子模块。
你的
1 2 3 | [submodule"SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git |
在Git存储库中有一个子模块对象(本例中名为SubmoduleStrepo)。Github将这些显示为"子模块"对象。或者从命令行执行
每当您执行EDOCX1[1]时,它将用提交中的内容填充子模块。由于
现在,
1 2 3 4 | [submodule"SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git branch = master |
编辑:上面只支持分支名称,不支持sha或tag。
子模块对象仍然指向特定的提交。
1 | git submodule update --remote |
它没有将子模块的内容填充到子模块指向的提交中,而是将该提交替换为主分支上的最新提交,然后用该提交填充子模块。Djacobs7答案可以分两步完成。由于您现在已经更新了子模块对象指向的提交,所以您必须将更改后的子模块对象提交到Git存储库中。
(2019年第2季度2.22吉特引进了
请注意,如果您有一个尚未跟踪分支的现有子模块,那么(如果您有Git 1.8.2+):
确保父回购协议知道其子模块现在跟踪分支:
1
2cd /path/to/your/parent/repo
git config -f .gitmodules submodule.<path>.branch <branch>确保您的子模块实际上是该分支的最新版本:
1
2
3
4cd path/to/your/submodule
git checkout -b branch --track origin/branch
# if the master branch already exist:
git branch -u origin/master master
&(a)(其中"origin"是克隆子模块的上游远程repo的名称。&(a)该子模块内的
不要忘记在您的父repo中记录子模块的新状态:
1
2
3cd /path/to/your/parent/repo
git add path/to/your/submodule
git commit -m"Make submodule tracking a branch"该子模块的后续更新必须使用
--remote 选项:1
2
3
4
5
6
7# 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季度),您可以使用'
The name of the branch is recorded as
submodule. in.branch .gitmodules forupdate --remote .
A special value of. is used to indicate that the name of the branch in the submodule should be the same name as the current branch in the current repository.
如果要更新分支后的所有子模块:
1 | git submodule update --recursive --remote |
请注意,对于每个更新的子模块,结果几乎总是一个独立的头,正如丹·卡梅伦在他的回答中指出的那样。
(clintm在评论中指出,如果运行
为了确保分支机构被实际签出(这不会修改代表父回购子模块的特殊条目的sha1),他建议:
1 | git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch' |
每个子模块仍然引用同一个sha1,但是如果您进行了新的提交,您将能够推送它们,因为它们将被您希望子模块跟踪的分支引用。在子模块内进行推送之后,不要忘记返回到父repo,为那些修改过的子模块添加、提交和推送新的sha1。
注意Alexander Pogrebnyak在评论中建议使用
it contains the absolute path of the top level directory (where
.gitmodules is).
The foreach script will fail to checkout submodules that are not following a branch.
However, this command gives you both:
1 | git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; ["$branch" ="" ] && git checkout master || git checkout $branch' – |
相同的命令,但更容易阅读:
1 2 3 4 | git submodule foreach -q --recursive \ 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \ ["$branch" ="" ] && \ git checkout master || git checkout $branch' – |
统一建模语言?UTE在注释中使用简化版本对dtmland的命令进行了优化:
1 | git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)' |
多线:
1 2 3 | git submodule foreach -q --recursive \ 'git checkout \ $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)' |
Git 1.8.2增加了跟踪分支的可能性。
1 2 3 4 5 | # 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子模块
一个如何使用Git子模块的示例。
看起来有点像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
也许它有帮助(即使我使用标签而不是分支)?
根据我的经验,无论子模块是否正确添加和跟踪(即@djacobs7和@johnny z answers),在超级项目中切换分支或未来签出仍将导致子模块的头分离。
而不是手动签出正确的分支,也可以使用脚本git foreach子模块。
这将检查branch属性的子模块配置文件并签出set branch。
Git子模块有点奇怪——它们总是处于"分离头"模式——它们不会像您预期的那样更新到分支上的最新提交。
不过,当你想到这一点时,这的确有些道理。假设我使用子模块栏创建存储库foo。我推送我的更改,并告诉您从存储库foo签出commit a7402be。
然后假设有人在您进行克隆之前提交了对存储库栏的更改。
当您从存储库foo签出commit a7402be时,您期望得到与我推送的代码相同的代码。这就是为什么子模块在您告诉它们显式地进行一次新的提交之前不会更新的原因。
我个人认为子模块是git中最容易混淆的部分。有很多地方可以比我更好地解释子模块。我推荐Scott Chacon的Pro Git。
要切换子模块的分支(假设您已经将子模块作为存储库的一部分):
cd 到包含子模块的存储库根目录- 打开
.gitmodules 进行编辑 - 在
path = ... 和url = ... 下为每个子模块添加一行,即branch = your-branch ;保存文件.gitmodules 。 - 然后在不更改目录的情况下执行
$ git submodule update --remote 。
…这应该为这样修改的每个子模块拉入指定分支上的最新提交。
我的.gitconfig文件中有这个。这仍然是草案,但到目前为止证明是有用的。它帮助我总是把子模块重新连接到它们的分支上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | [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 = [email protected]/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存储库中提取特定模块。我们需要在不使用所提供存储库的整个代码库的情况下提取代码——我们需要从这个庞大的存储库中提取一个非常具体的模块/文件,并且每次运行更新时都应该对其进行更新。
所以我们是这样实现的:
创建配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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存储库中创建第一个模块配置中指定的一个目录,另一个目录是从给定的存储库中提取和创建文件。
其他开发人员只需要运行
1 | $ quack |
它从上面的配置中提取代码。
为子模块选择分支的唯一效果是,每当您在
如果您使用子模块的浅克隆,那么在为Git子模块使用此远程分支跟踪功能时必须特别小心。在子模块设置中为此目的选择的分支不是将在
毫不奇怪,在
fatal: Needed a single revision
Unable to find current origin/NotThePrimaryBranch revision in submodule path 'mySubmodule'
git子模块add-b develop--name分支名称--https://branch.git