添加 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 07:22:51  来源:igfitidea点击:

How can I specify a branch/tag when adding a Git submodule?

gitgit-submodules

提问by Ivan

How does git submodule add -bwork?

如何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 statuson the submodule shows "Not currently on any branch").

添加具有特定分支的子模块后,新的克隆存储库(之后git submodule update --init)将处于特定提交,而不是分支本身(git status在子模块上显示“当前不在任何分支上”)。

I can't find any information on .gitmodulesor .git/configabout 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 pullchanges which commit their submodule directory points to. git submodule updateactually 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 子模块。

  1. Your .gitmoduleshas an entry like so:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. You have a submodule object (named SubmoduleTestRepo in this example) in your Git repository. GitHubshows these as "submodule" objects. Or do git submodule statusfrom 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 -bdoes is add one line in your .gitmodulesfile. 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 .gitmodulesfile, 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 .gitmodulesfile each time)

    The submodule object is still pointing at a specific commit. The only thing that the -boption buys you is the ability to add a --remoteflag 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 -bis not some magically way to keep everything up to date with a branch. It is simply adds information about a branch in the .gitmodulesfile and gives you the option to update the submodule object to the latest commit of a specified branch before populating it.

  1. .gitmodules有一个像这样的条目:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. 您的 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 .”来跟踪和更新每个模块的分支提交,例如 like git 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 -vinside 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 --remoteoption:

    # 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>.branchin .gitmodulesfor update --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.gitmodulesupdate --remote
一个特殊的值.用于指示子模块中分支的名称应与当前存储库中的当前分支名称相同

But, as commentedby LubosD

但是,正如LubosD所评论那样

With git checkout, if the branch name to follow is ".", it will kill your uncommitted work!
Use git switchinstead.

使用git checkout,如果要遵循的分支名称是“ .”,它将杀死您未提交的工作!
使用git switch来代替。

That means Git 2.23 (August 2019) or more.

这意味着 Git 2.23(2019 年 8 月)或更高版本。

See "Confused by git checkout"

见“困惑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 --remoteand 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.
$toplevelwas 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 .gitmodulesis).

它包含顶级目录的绝对路径(在哪里.gitmodules)。

dtmlandadds in the comments:

dtmland在评论中添加:

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 fetch

Signed-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 by run_processes_parallel,mutexing is not required around submodules_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 子模块的示例。

  1. Create a new repository
  2. Then clone another repository as a submodule
  3. Then we have that submodule use a tag called V3.1.2
  4. And then we commit.
  1. 创建一个新的存储库
  2. 然后将另一个存储库克隆为子模块
  3. 然后我们让该子模块使用一个名为 V3.1.2 的标签
  4. 然后我们承诺。

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):

要为子模块切换分支(假设您已经将子模块作为存储库的一部分):

  • cdto root of your repository containing the submodules
  • Open .gitmodulesfor editing
  • Add line below path = ...and url = ...that says branch = 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.

它从上述配置中提取代码。