添加 Git 子模块时如何指定分支/标签?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1777854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I specify a branch/tag when adding a Git submodule?
提问by Ivan
How does git submodule add -b
work?
如何git submodule add -b
工作?
After adding a submodule with a specific branch, a new cloned repository (after git submodule update --init
) will be at a specific commit, not the branch itself (git status
on the submodule shows "Not currently on any branch").
添加具有特定分支的子模块后,新的克隆存储库(之后git submodule update --init
)将处于特定提交,而不是分支本身(git status
在子模块上显示“当前不在任何分支上”)。
I can't find any information on .gitmodules
or .git/config
about the submodule's branch or any specific commit, so how does Git figure it out?
我无法找到任何信息.gitmodules
或.git/config
关于子模块的分支或任何具体的承诺,它是如何与Git的数字出来?
Also, is it possible to specify a tag instead of a branch?
另外,是否可以指定标签而不是分支?
I'm using version 1.6.5.2.
我使用的是 1.6.5.2 版。
采纳答案by djacobs7
Note: Git 1.8.2 added the possibility to track branches. See some of the answers below.
注意:Git 1.8.2 添加了跟踪分支的可能性。请参阅下面的一些答案。
It's a little confusing to get used to this, but submodules are not on a branch. They are, like you say, just a pointer to a particular commit of the submodule's repository.
习惯这一点有点令人困惑,但子模块不在分支上。就像您说的那样,它们只是指向子模块存储库的特定提交的指针。
This means, when someone else checks out your repository, or pulls your code, and does git submodule update, the submodule is checked out to that particular commit.
这意味着,当其他人检出您的存储库或提取您的代码并执行 git submodule update 时,子模块将检出到该特定提交。
This is great for a submodule that does not change often, because then everyone on the project can have the submodule at the same commit.
这对于不经常更改的子模块非常有用,因为项目中的每个人都可以在同一个提交中拥有子模块。
If you want to move the submodule to a particular tag:
如果要将子模块移动到特定标签:
cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push
Then, another developer who wants to have submodule_directory changed to that tag, does this
然后,另一个想要将 submodule_directory 更改为该标记的开发人员执行此操作
git pull
git submodule update --init
git pull
changes which commit their submodule directory points to. git submodule update
actually merges in the new code.
git pull
提交其子模块目录指向的更改。 git submodule update
实际上合并到新代码中。
回答by Johnny Z
I'd like to add an answer here that is really just a conglomerate of other answers, but I think it may be more complete.
我想在这里添加一个答案,它实际上只是其他答案的集合,但我认为它可能更完整。
You know you have a Git submodule when you have these two things.
当你有这两个东西时,你就知道你有一个 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. GitHubshows 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 likegit 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.
你
.gitmodules
有一个像这样的条目:[submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git
您的 Git 存储库中有一个子模块对象(在本示例中名为 SubmoduleTestRepo)。GitHub 将这些显示为“子模块”对象。或者
git submodule status
从命令行执行。Git 子模块对象是特殊类型的 Git 对象,它们保存特定提交的 SHA 信息。每当您执行 a 时
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
它不是将子模块的内容填充到子模块指向的提交,而是用主分支上的最新提交替换该提交,然后用该提交填充子模块。这可以通过 djacobs7 answer 分两步完成。由于您现在已经更新了子模块对象指向的提交,因此您必须将更改的子模块对象提交到您的 Git 存储库中。
git submodule add -b
不是通过分支使所有内容保持最新的神奇方式。它只是在.gitmodules
文件中添加有关分支的信息,并为您提供在填充之前将子模块对象更新为指定分支的最新提交的选项。
回答by VonC
(Git 2.22, Q2 2019, has introduced git submodule set-branch --branch aBranch -- <submodule_path>
)
(Git 2.22,Q2 2019,已经引入git submodule set-branch --branch aBranch -- <submodule_path>
)
Note that if you have an existingsubmodule which isn'ttracking a branch yet, then (if you have git 1.8.2+):
请注意,如果您有一个尚未跟踪分支的现有子模块,那么(如果您有 git 1.8.2+):
Make sure the parent repo knows that its submodule now tracks a branch:
cd /path/to/your/parent/repo git config -f .gitmodules submodule.<path>.branch <branch>
Make sure your submodule is actually at the latest of that 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
确保父仓库知道它的子模块现在跟踪一个分支:
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
(with 'origin' being the name of the upstream remote repothe submodule has been cloned from.
A git remote -v
inside that submodule will display it. Usually, it is 'origin')
(与“原点”是的名称上游远程回购子模块已从。克隆
甲git remote -v
内部的子模块将其显示。通常,它是“原点”)
Don't forget to record the new state of your submodule in your parent repo:
cd /path/to/your/parent/repo git add path/to/your/submodule git commit -m "Make submodule tracking a branch"
Subsequent update for that submodule will have to use the
--remote
option:# 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
不要忘记在父仓库中记录子模块的新状态:
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
Note that with Git 2.10+(Q3 2016), you can use '.
' as a branch name:
请注意,在Git 2.10+(2016 年第 3 季度)中,您可以使用“ .
”作为分支名称:
The name of the branch is recorded as
submodule.<name>.branch
in.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.
分支的名称记录
submodule.<name>.branch
在.gitmodules
了update --remote
。
一个特殊的值.
用于指示子模块中分支的名称应与当前存储库中的当前分支名称相同。
But, as commentedby LubosD
With
git checkout
, if the branch name to follow is ".
", it will kill your uncommitted work!
Usegit switch
instead.
使用
git checkout
,如果要遵循的分支名称是“.
”,它将杀死您未提交的工作!
使用git switch
来代替。
That means Git 2.23 (August 2019) or more.
这意味着 Git 2.23(2019 年 8 月)或更高版本。
See "Confused by git checkout
"
If you want to update all your submodules following a branch:
如果要更新分支后的所有子模块:
git submodule update --recursive --remote
Note that the result, for each updated submodule, will almost always be a detached HEAD, as Dan Cameronnote in his answer.
请注意,对于每个更新的子模块,结果几乎总是一个分离的 HEAD,正如Dan Cameron在他的回答中指出的那样。
(Clintmnotes in the commentsthat, if you run git submodule update --remote
and the resulting sha1 is the same as the branch the submodule is currently on, it won't do anything and leave the submodule still "on that branch" and not in detached head state.)
(Clintm笔记的意见是,如果你运行git submodule update --remote
所得SHA1是一样的分支目前的子模块上,它不会“对分支”做任何事情,离开子模块仍而不是分离的头的状态。 )
To ensure the branch is actually checked out (and that won't modify the SHA1 of the special entryrepresenting the submodule for the parent repo), he suggests:
为了确保分支实际被检出(并且不会修改代表父存储库子模块的特殊条目的 SHA1 ),他建议:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'
Each submodule will still reference the same SHA1, but if you do make new commits, you will be able to push them because they will be referenced by the branch you want the submodule to track.
After that push within a submodule, don't forget to go back to the parent repo, add, commit and push the new SHA1 for those modified submodules.
每个子模块仍将引用相同的 SHA1,但如果您确实进行了新提交,您将能够推送它们,因为它们将被您希望子模块跟踪的分支引用。
在子模块中推送之后,不要忘记返回父存储库,为那些修改过的子模块添加、提交和推送新的 SHA1。
Note the use of $toplevel
, recommended in the commentsby Alexander Pogrebnyak.$toplevel
was introduced in git1.7.2 in May 2010: commit f030c96.
使用注意事项$toplevel
,建议在评论由亚历山大Pogrebnyak。$toplevel
于 2010 年 5 月在 git1.7.2 中引入:commit f030c96。
it contains the absolute path of the top level directory (where
.gitmodules
is).
它包含顶级目录的绝对路径(在哪里
.gitmodules
)。
dtmland
adds in the comments:
The foreach script will fail to checkout submodules that are not following a branch.
However, this command gives you both:
foreach 脚本将无法检出未遵循分支的子模块。
但是,此命令为您提供:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git switch $branch' –
The same command but easier to read:
相同的命令但更易于阅读:
git submodule foreach -q --recursive \
'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
[ "$branch" = "" ] && \
git checkout master || git switch $branch' –
uml?uterefines dtmland's command with a simplified version in the comments:
uml?ute在评论中使用简化版本改进了dtmland的命令:
git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
multiple lines:
多行:
git submodule foreach -q --recursive \
'git switch \
$(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
Before Git 2.26 (Q1 2020), a fetch that is told to recursively fetch updates in submodules inevitably produces reams of output, and it becomes hard to spot error messages.
在 Git 2.26(2020 年第一季度)之前,被告知在子模块中递归获取更新的获取不可避免地会产生大量输出,并且很难发现错误消息。
The command has been taught to enumerate submodules that had errors at the end of the operation.
该命令已被教导枚举在操作结束时出现错误的子模块。
See commit 0222540(16 Jan 2020) by Emily Shaffer (nasamuffin
).
(Merged by Junio C Hamano -- gitster
--in commit b5c71cc, 05 Feb 2020)
请参阅Emily Shaffer ( ) 的提交 0222540(2020 年 1 月 16 日)。(由Junio C Hamano合并-- --在提交 b5c71cc 中,2020 年 2 月 5 日)nasamuffin
gitster
fetch
: emphasize failure during submodule fetchSigned-off-by: Emily Shaffer
In cases when a submodule fetch fails when there are many submodules, the error from the lone failing submodule fetch is buried under activity on the other submodules if more than one fetch fell back on
fetch-by-oid
.
Call out a failure late so the user is aware that something went wrong, and where.Because
fetch_finish()
is only called synchronously byrun_processes_parallel,
mutexing is not required aroundsubmodules_with_errors
.
fetch
: 在子模块获取期间强调失败签字人:Emily Shaffer
在有许多子模块时子模块提取失败的情况下,如果多个提取返回到 ,则单独失败的子模块提取的错误会被其他子模块的活动所掩盖
fetch-by-oid
。
晚点调用失败,以便用户知道出了什么问题,以及哪里出了问题。因为
fetch_finish()
只被run_processes_parallel,
互斥锁同步调用,所以周围不需要submodules_with_errors
。
回答by vogella
Git 1.8.2 added the possibility to track branches.
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
See also Git submodules
另请参阅Git 子模块
回答by Johan
An example of how I use Git submodules.
我如何使用 Git 子模块的示例。
- Create a new repository
- Then clone another repository as a submodule
- Then we have that submodule use a tag called V3.1.2
- And then we commit.
- 创建一个新的存储库
- 然后将另一个存储库克隆为子模块
- 然后我们让该子模块使用一个名为 V3.1.2 的标签
- 然后我们承诺。
And that looks a little bit like this:
这看起来有点像这样:
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
Maybe it helps (even though I use a tag and not a branch)?
也许它有帮助(即使我使用标签而不是分支)?
回答by Dan Cameron
In my experience switching branches in the superproject or future checkouts will still cause detached HEADs of submodules regardless if the submodule is properly added and tracked (i.e. @djacobs7 and @Johnny Z answers).
根据我的经验,无论是否正确添加和跟踪子模块(即 @djacobs7 和 @Johnny Z 答案),切换超级项目中的分支或将来的结帐仍会导致子模块的 HEAD 分离。
And instead of manually checking out the correct branch manually or through a script git submodule foreachcan be used.
并且可以使用git submodule foreach代替手动或通过脚本手动检出正确的分支。
This will check the submodule config file for the branch property and checkout the set branch.
这将检查分支属性的子模块配置文件并检出设置分支。
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
回答by Neall
Git submodules are a little bit strange - they're always in "detached head" mode - they don't update to the latest commit on a branch like you might expect.
Git 子模块有点奇怪——它们总是处于“分离头”模式——它们不会像你期望的那样更新到分支上的最新提交。
This does make some sense when you think about it, though. Let's say I create repository foowith submodule bar. I push my changes and tell you to check out commit a7402be from repository foo.
不过,当你考虑它时,这确实是有道理的。假设我使用子模块bar创建存储库foo。我推送我的更改并告诉您从存储库foo检查提交 a7402be 。
Then imagine that someone commits a change to repository barbefore you can make your clone.
然后想象有人在您可以进行克隆之前提交了对存储库栏的更改。
When you check out commit a7402be from repository foo, you expect to get the same code I pushed. That's why submodules don't update until you tell them to explicitly and then make a new commit.
当您从存储库foo检出提交 a7402be 时,您希望获得与我推送的相同的代码。这就是为什么子模块在您明确告诉它们然后进行新提交之前不会更新的原因。
Personally I think submodules are the most confusing part of Git. There are lots of places that can explain submodules better than I can. I recommend Pro Gitby Scott Chacon.
我个人认为子模块是 Git 中最令人困惑的部分。有很多地方可以比我更好地解释子模块。我推荐Scott Chacon 的Pro Git。
回答by Engineer
To switch branch for a submodule (assuming you already have the submodule as part of the repository):
要为子模块切换分支(假设您已经将子模块作为存储库的一部分):
cd
to root of your repository containing the submodules- Open
.gitmodules
for editing - Add line below
path = ...
andurl = ...
that saysbranch = your-branch
, for each submodule; save file.gitmodules
. - then without changing directory do
$ git submodule update --remote
cd
到包含子模块的存储库的根目录- 打开
.gitmodules
编辑 - 加入线下
path = ...
和url = ...
,说branch = your-branch
,对每个子模块; 保存文件.gitmodules
。 - 然后不改变目录做
$ git submodule update --remote
...this should pull in the latest commits on the specified branch, for each submodule thus modified.
...这应该为每个修改后的子模块拉入指定分支上的最新提交。
回答by Pascal T.
I have this in my .gitconfig file. It is still a draft, but proved useful as of now. It helps me to always reattach the submodules to their 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 = [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-"
回答by Love Sharma
We use Quackto pull a specific module from another Git repository. We need to pull code without the whole code base of the provided repository - we need a very specific module / file from that huge repository and should be updated every time we run update.
我们使用Quack从另一个 Git 存储库中提取特定模块。我们需要在没有提供的存储库的整个代码库的情况下提取代码——我们需要从那个巨大的存储库中获取一个非常具体的模块/文件,并且每次运行更新时都应该更新。
So we achieved it in this way:
所以我们是这样实现的:
Create configuration
创建配置
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']
With the above configuration, it creates one directory from the provided GitHub repository as specified in first module configuration, and the other one is to pull and create a file from the given repository.
通过上述配置,它从提供的 GitHub 存储库中创建一个目录,如第一个模块配置中指定的那样,另一个是从给定的存储库中拉取并创建一个文件。
Other developers just need to run
其他开发者只需要运行
$ quack
And it pulls the code from the above configurations.
它从上述配置中提取代码。