添加 Git 子模块时如何指定分支/标签?

发布于 2024-08-12 05:44:12 字数 297 浏览 4 评论 0原文

git submodule add -b 是如何工作的?

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

我在 .gitmodules.git/config 上找不到有关子模块分支或任何特定提交的任何信息,那么 Git 是如何弄清楚的呢?

另外,是否可以指定标签而不是分支?

How does git submodule add -b work?

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").

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?

Also, is it possible to specify a tag instead of a branch?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

乖乖公主 2024-08-19 05:44:12

我想在这里添加一个答案,它实际上只是其他答案的集合,但我认为它可能更完整。

当你拥有这两个东西时,你就知道你拥有了一个 Git 子模块。

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

    [子模块“SubmoduleTestRepo”]
        路径 = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
  2. 您的 Git 存储库中有一个子模块对象(在本示例中名为 SubmoduleTestRepo)。 GitHub 将这些显示为“子模块”对象。或者从命令行执行git submodule status。 Git 子模块对象是特殊类型的 Git 对象,它们保存特定提交的 SHA 信息。

    每当您执行 git 子模块更新时,它都会使用提交中的内容填充您的子模块。由于 .gitmodules 中的信息,它知道在哪里可以找到提交。

    现在,-b 所做的只是在 .gitmodules 文件中添加一行。因此,按照相同的示例,它看起来像这样:

    [子模块“SubmoduleTestRepo”]
        路径 = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
        分支=主控
    

    <块引用>

    注意: .gitmodules 文件中仅支持分支名称,但不支持 SHA 和 TAG! (相反,可以使用“git add .”来跟踪和更新每个模块的分支提交,例如git add ./SubmoduleTestRepo,并且您不需要更改< code>.gitmodules 每次文件)

    子模块对象仍然指向特定的提交。 -b 选项为您带来的唯一好处是能够根据 Vogella 的回答向您的更新添加 --remote 标志:

    git 子模块更新 --remote
    

    它不是将子模块的内容填充到子模块指向的提交,而是用主分支上的最新提交替换该提交,然后用该提交填充子模块。这可以通过 djacobs7 答案分两步完成。由于您现在已经更新了子模块对象指向的提交,因此您必须将更改的子模块对象提交到您的 Git 存储库中。

    git submodule add -b 并不是让分支中的所有内容保持最新的神奇方法。它只是在 .gitmodules 文件中添加有关分支的信息,并为您提供了在填充子模块对象之前将其更新为指定分支的最新提交的选项。

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.

  1. Your .gitmodules has 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. GitHub shows 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 like git 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.

为你拒绝所有暧昧 2024-08-19 05:44:12

注意: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 实际上合并到了新代码中。

Note: Git 1.8.2 added the possibility to track branches. See some of the answers below.


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.

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

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.

不奢求什么 2024-08-19 05:44:12

(Git 2.22,2019 年第 2 季度,引入了 git submodule set-branch --branch aBranch --

请注意,如果您有一个现有子模块尚未跟踪分支,那么(如果您有 git 1.8.2+):

  • 确保父存储库知道其子模块现在跟踪分支:

     cd /path/to/your/parent/repo
      git config -f .gitmodules submodule..branch ;
    
  • 确保您的子模块实际上位于该分支的最新版本:

     cd 路径/到/你的/子模块
      git checkout -b 分支 --track origin/branch
        # 如果分支已经存在:
        git 分支 -u 原点/分支 分支
    

        
(“origin”是子模块已克隆的上游远程存储库的名称.
      
该子模块内的 git remote -v 将会显示它。通常,它是“origin”)

  • 不要忘记在父存储库中记录子模块的新状态:

     cd /path/to/your/parent/repo
      git 添加路径/到/你的/子模块
      git commit -m“使子模块跟踪分支”
    
  • 该子模块的后续更新必须使用 --remote 选项:

     # 更新你的子模块
      # --remote 还将获取并确保
      # 使用分支的最新提交
      git 子模块更新 --remote
    
      # 避免获取使用
      git 子模块更新 --remote --no-fetch 
    

Lolorol 建议 < a href="https://stackoverflow.com/questions/1777854/how-can-i-specify-a-branch-tag-when-adding-a-git-submodule/18799234?noredirect=1#comment133707993_18799234">注释在每个子模块中设置分支:

git submodule update --init --recursive
git submodule foreach -q --recursive \
  'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch ${branch}'
git submodule

请注意,使用 Git 2.10+ (2016 年第 3 季度),您可以使用“.”作为分支名称:

分支的名称在.gitmodules中记录为submodule..branch,用于update --remote。< br>
特殊值.用于指示子模块中的分支名称应与当前存储库中的当前分支名称相同

但是,评论 作者:LubosD

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

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

请参阅“Confused by git checkout”:


如果您想更新分支后的所有子模块,

    git submodule update --recursive --remote

请注意,对于每个更新的子模块,结果几乎总是一个分离的 HEAD,如下所示丹·卡梅伦中的注释他的回答

Clintm 注释在注释中,如果运行 git submodule update --remote 且生成的 sha1 与子模块当前所在的分支相同打开,它不会执行任何操作,并使子模块仍然“在该分支上”,而不是处于分离的头状态。)

为了确保分支实际上已签出(并且不会修改 特殊条目代表父存储库的子模块),他建议:

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'

每个子模块仍将引用相同的 SHA1,但是如果您确实进行了新的提交,您将能够推送它们,因为它们将被您希望子模块跟踪的分支引用。
在子模块内推送之后,不要忘记返回父存储库,为那些修改的子模块添加、提交并推送新的 SHA1。

请注意 $toplevel 的使用,推荐 Alexander Pogrebnyak 的评论。
$toplevel 于 2010 年 5 月在 git1.7.2 中引入:commit f030c96。

它包含顶级目录的绝对路径(其中 .gitmodules 所在)。

dtmland 添加了在评论中

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(2020 年第一季度)之前,被告知以递归方式获取子模块中的更新的获取不可避免地会产生大量输出,并且它变得很难发现错误消息。

该命令已被教导枚举在操作结束时出现错误的子模块

请参阅 提交 0222540(2020 年 1 月 16 日),作者:艾米丽·谢弗 (nasamuffin)
(由 Junio C Hamano -- gitster -- 合并于 提交 b5c71cc,2020 年 2 月 5 日)

fetch:强调子模块获取期间失败

签字人:Emily Shaffer

当存在多个子模块时子模块提取失败时,如果多个提取退回到fetch-by-oid.
晚点发出故障,以便用户知道出了问题以及出问题的位置

由于 fetch_finish() 仅由 run_processes_parallel 同步调用,因此 submodules_with_errors 周围不需要互斥。



请注意,在 Git 2.28(2020 年第 3 季度)中,脚本化“git 子模块”Porcelain 命令的部分内容将继续重写;这次是“git submodule set-branch”子命令的转动。

请参阅 提交 2964d6e(2020 年 6 月 2 日),作者:Shourya Shukla (periperidip)
(由 Junio C Hamano -- gitster -- 合并于 提交 1046282,2020 年 6 月 25 日)

子模块:端口子命令'set-branch'从 shell 到 C

指导者:Christian Couder
指导者:Kaartic Sivaraam
帮助者:刘丹顿
帮助者:Eric Sunshine
帮助者:Đoàn Trần Công Danh
签署人:Shourya Shukla

将子模块子命令“set-branch”转换为内置命令并通过 git submodule.sh 调用它。


Git 2.43(2023 年第 4 季度)处理重命名的子模块:在 .gitmodules 文件中,子模块由其名称作为关键字,名称为 $name 的子模块的路径由 submodule.$ 指定。 name.path 变量。

在查询子模块数据库时,有一些代码路径混合了名称和路径,这些代码路径已得到纠正。

这些错误花了很长时间才被发现,因为子模块的名称最初与其路径相同,并且直到将其移动到不同的路径时问题才会出现,而这种情况显然很少发生。

请参阅提交bd1c20c提交 32bff36提交 5fc8806、提交 b027fb0提交 387c122, 提交 6327085 (2023 年 10 月 3 日)作者:Jan Alexander Steffens (heftig) (heftig).
(由 Junio C Hamano -- gitster -- 合并于 提交 b32f5b6,2023 年 10 月 13 日)

t7419:测试我们是否正确处理重命名的子模块

签字人:Jan Alexander Steffens (heftig)

使用明确不同的名称和路径再次添加子模块。
测试调用 set-branch 是否修改了正确的 .gitmodules 条目。
确保我们不会创建以路径而不是名称命名的部分。

(Git 2.22, Q2 2019, has introduced git submodule set-branch --branch aBranch -- <submodule_path>)

Note that if you have an existing submodule which isn't tracking a branch yet, then (if you have 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 branch already exist:
        git branch -u origin/branch branch
    

(with 'origin' being the name of the upstream remote repo the submodule has been cloned from.

A git remote -v inside that submodule will display it. Usually, it is 'origin')

  • 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 
    

Lolorol suggests in the comments to set the branch in each submodule:

git submodule update --init --recursive
git submodule foreach -q --recursive \
  'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch ${branch}'
git submodule

Note that with Git 2.10+ (Q3 2016), you can use '.' as a branch name:

The name of the branch is recorded as submodule.<name>.branch in .gitmodules for 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.

But, as commented by LubosD

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

That means Git 2.23 (August 2019) or more.

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 Cameron note in his answer.

(Clintm notes in the comments that, 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.)

To ensure the branch is actually checked out (and that won't modify the SHA1 of the special entry representing the submodule for the parent repo), he suggests:

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.

Note the use of $toplevel, recommended in the comments by Alexander Pogrebnyak.
$toplevel was introduced in git1.7.2 in May 2010: commit f030c96.

it contains the absolute path of the top level directory (where .gitmodules is).

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:

 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äute refines dtmland's command with a simplified version in the comments:

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.

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)

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.


Note that, with Git 2.28 (Q3 2020), Rewrite of parts of the scripted "git submodule" Porcelain command continues; this time it is "git submodule set-branch" subcommand's turn.

See commit 2964d6e (02 Jun 2020) by Shourya Shukla (periperidip).
(Merged by Junio C Hamano -- gitster -- in commit 1046282, 25 Jun 2020)

submodule: port subcommand 'set-branch' from shell to C

Mentored-by: Christian Couder
Mentored-by: Kaartic Sivaraam
Helped-by: Denton Liu
Helped-by: Eric Sunshine
Helped-by: Đoàn Trần Công Danh
Signed-off-by: Shourya Shukla

Convert submodule subcommand 'set-branch' to a builtin and call it via git submodule.sh.


Git 2.43 (Q4 2023) handles renamed submodules: in .gitmodules files, submodules are keyed by their names, and the path to the submodule whose name is $name is specified by the submodule.$name.path variable.

There were a few codepaths that mixed the name and path up when consulting the submodule database, which have been corrected.

It took long for these bugs to be found as the name of a submodule initially is the same as its path, and the problem does not surface until it is moved to a different path, which apparently happens very rarely.

See commit bd1c20c, commit 32bff36, commit 5fc8806, commit b027fb0, commit 387c122, commit 6327085 (03 Oct 2023) by Jan Alexander Steffens (heftig) (heftig).
(Merged by Junio C Hamano -- gitster -- in commit b32f5b6, 13 Oct 2023)

t7419: test that we correctly handle renamed submodules

Signed-off-by: Jan Alexander Steffens (heftig)

Add the submodule again with an explicitly different name and path.
Test that calling set-branch modifies the correct .gitmodules entries.
Make sure we don't create a section named after the path instead of the name.

蓦然回首 2024-08-19 05:44:12

Git 1.8.2 添加了跟踪分支的可能性。

# add submodule to track branch_name branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

另请参阅 Git 子模块

Git 1.8.2 added the possibility to track branches.

# add submodule to track branch_name 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

臻嫒无言 2024-08-19 05:44:12

我如何使用 Git 子模块的示例。

  1. 创建一个新的存储库
  2. 然后将另一个存储库克隆为子模块
  3. 然后我们让该子模块使用名为 V3.1.2 的标签
  4. 然后我们提交。

这看起来有点像这样:

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 

也许它有帮助(即使我使用标签而不是分支)?

An example of how I use Git submodules.

  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.

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

现有答案缺少第二步,并且细节过多。

要切换现有子模块以跟踪新的远程 URL 和/或新分支:

  1. 编辑 .gitmodules 中的事实来源代码>.

例如, from

[submodule "api"]
    path = api
    url = https://github.com/<original_repo>/api.git

[submodule "api"]
    path = api
    url = https://github.com/<another_repo>/api.git
    branch = work-in-progress

您还可以使用 hexsha 作为提交哈希。或 tag,但请参阅 3.

  1. git submodulesync:从 .git/modules 更新 git 缓存的子模块的描述刚刚编辑的事实来源在 .gitmodules 中指定。

  2. 仅当您指定标签时:git submodule foreach --recursive 'git fetch --tags' 才能获取标签。

  3. git submodule update --init --recursive --remote:更新工作副本中签出的子模块。

  4. 提交更改。

Existing answers have the second step missing and overloaded with details.

To switch an existing submodule to track a new remote url and/or a new branch:

  1. Edit the source of truth in .gitmodules.

For example, from

[submodule "api"]
    path = api
    url = https://github.com/<original_repo>/api.git

to

[submodule "api"]
    path = api
    url = https://github.com/<another_repo>/api.git
    branch = work-in-progress

You can also use hexsha for a commit hash. Or tag, but see 3.

  1. git submodule sync: Updates the description of submodules cached by git in .git/modules from the just-edited source of truth specified in .gitmodules.

  2. Only if you specify a tag: git submodule foreach --recursive 'git fetch --tags' to fetch tags.

  3. git submodule update --init --recursive --remote: Updates the checked-out submodules in the working copy.

  4. Commit the changes.

夜访吸血鬼 2024-08-19 05:44:12

Git 子模块有点奇怪 - 它们总是处于“分离头”模式 - 它们不会像您期望的那样更新到分支上的最新提交。

不过,仔细想想,这确实有一定道理。假设我使用子模块 bar 创建存储库 foo。我推送我的更改并告诉您从存储库 foo 中查看提交 a7402be。

然后想象一下,在您进行克隆之前,有人向存储库提交了更改bar

当您从存储库 foo 中签出提交 a7402be 时,您希望获得与我推送的代码相同的代码。这就是为什么子模块不会更新,直到您明确告诉它们然后进行新的提交。

我个人认为子模块是 Git 中最令人困惑的部分。有很多地方可以比我更好地解释子模块。我推荐 Scott Chacon 的 Pro Git

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.

This does make some sense when you think about it, though. Let's say I create repository foo with submodule bar. I push my changes and tell you to check out commit a7402be from repository foo.

Then imagine that someone commits a change to repository bar before 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.

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 Git by Scott Chacon.

薄情伤 2024-08-19 05:44:12

根据我的经验,在超级项目中切换分支或将来的签出仍然会导致子模块分离 HEAD,无论子模块是否正确添加和跟踪(即 @djacobs7 和 @Johnny Z 答案)。

而不是手动或通过脚本手动检查正确的分支 git 子模块 foreach

这将检查子模块配置文件的分支属性并签出设置的分支。

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel.gitmodules submodule.$name.branch)"; git checkout $branch'

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

And instead of manually checking out the correct branch manually or through a script git submodule foreach can be used.

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 $toplevel.gitmodules submodule.$name.branch)"; git checkout $branch'

困倦 2024-08-19 05:44:12

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

  • cd 到包含子模块的存储库的根目录
  • 打开 .gitmodules 进行编辑
  • 添加行对于每个子模块,在 path = ...url = ... 下方表示 branch = your-branch;保存文件 .gitmodules
  • 然后在不更改目录的情况下执行 $ git submodule update --remote

...这应该为每个修改的子模块拉取指定分支上的最新提交。

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 = ... and url = ... that says branch = your-branch, for each submodule; save file .gitmodules.
  • then without changing directory do $ git submodule update --remote

...this should pull in the latest commits on the specified branch, for each submodule thus modified.

请叫√我孤独 2024-08-19 05:44:12

我的 .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-"

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.

[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-"
独自←快乐 2024-08-19 05:44:12

为子模块选择分支的唯一效果是,每当您在 git submodule update 命令行中传递 --remote 选项时,Git 都会在 分离 HEAD 模式(如果选择默认的 --checkout 行为)所选远程分支的最新提交。

如果您使用子模块的浅克隆,则在对 Git 子模块使用此远程分支跟踪功能时必须特别小心。
您在子模块设置中为此目的选择的分支不是将在git submodule update --remote期间克隆的分支。
如果您还传递了 --depth 参数,并且您不会指示 Git 您要克隆哪个分支 -- 实际上您不能 git submodule update 命令行!! -- ,当显式 --branch< 时,它会隐式地表现得像 git-clone(1) 文档中为 git clone --single-branch 所解释的那样/code> 参数丢失,因此它将仅克隆主分支

毫不奇怪,在 git submodule update 命令执行克隆阶段之后,它最终会尝试检查您之前为 git submodule update 设置的 remote 分支的最新提交。子模块,并且,如果这不是主要模块,则它不是本地浅克隆的一部分,因此它将失败

致命:需要一次修改

无法在子模块路径“mySubmodule”中找到当前源/NotThePrimaryBranch修订版

The only effect of choosing a branch for a submodule is that, whenever you pass the --remote option in the git submodule update command line, Git will check out in detached HEAD mode (if the default --checkout behavior is selected) the latest commit of that selected remote branch.

You must be particularly careful when using this remote branch tracking feature for Git submodules if you work with shallow clones of submodules.
The branch you choose for this purpose in submodule settings IS NOT the one that will be cloned during git submodule update --remote.
If you pass also the --depth parameter and you do not instruct Git about which branch you want to clone -- and actually you cannot in the git submodule update command line!! -- , it will implicitly behave like explained in the git-clone(1) documentation for git clone --single-branch when the explicit --branch parameter is missing, and therefore it will clone the primary branch only.

With no surprise, after the clone stage performed by the git submodule update command, it will finally try to check out the latest commit for the remote branch you previously set up for the submodule, and, if this is not the primary one, it is not part of your local shallow clone, and therefore it will fail with

fatal: Needed a single revision

Unable to find current origin/NotThePrimaryBranch revision in submodule path 'mySubmodule'

萌︼了一个春 2024-08-19 05:44:12

我们使用 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

它就会从上面的配置中提取代码。

We use Quack to 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.

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.

Other developers just need to run

$ quack

And it pulls the code from the above configurations.

忱杏 2024-08-19 05:44:12

git子模块添加-b开发--name分支名称--https://branch.git

git submodule add -b develop --name branch-name -- https://branch.git

七分※倦醒 2024-08-19 05:44:12

就目前而言,在 2023 年,它对我来说效果很好:

git submodule add -bbranch_name -- ssh://submodule_url.git deps/submodule_location

正如 git 文档所示 https://git-scm.com/docs/git-submodule
add [-b <分支>] [-f|--force] [--name <名称>] [--引用 <存储库>] [--深度 <深度>] [-- ] <存储库> [<路径>]

As for now, in 2023, it works fine for me doing:

git submodule add -b branch_name -- ssh://submodule_url.git deps/submodule_location

As it shows on git documentation https://git-scm.com/docs/git-submodule:
add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]

甜心 2024-08-19 05:44:12

回到最初的问题,“添加 Git 子模块时如何指定分支/标签?”,假设我在 .gitmodules 文件中指定一个标签:

[submodule "module1"]
    path = module1
    url = https://github.com/<my-org>/module1
    tag = v0.0.1
[submodule "module2"]
    path = module2
    url = https://github.com/<my-org>/module2
    tag = v0.0.1

在克隆/初始化之后,您可以使用 (PowerShell/ Bash):

git submodule foreach 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.tag)'

或者,如果您只想查看 .gitmodules 中的子模块标签,而不进行结帐:

git submodule foreach 'git config -f $toplevel/.gitmodules submodule.$name.tag'

最后,使用 .gitmodules 中的标签,或者如果 .gitmodules 中没有找到,则默认为最新标签:

git submodule foreach 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.tag || git describe --tags $(git rev-list --tags --max-count=1))'

请注意,从 cmd 运行时,这些命令将失败。EXE文件!使用 Powershell 或 bash。

Going back to the original question, "How can I specify a branch/tag when adding a Git submodule?", suppose I specify a tag in the .gitmodules file:

[submodule "module1"]
    path = module1
    url = https://github.com/<my-org>/module1
    tag = v0.0.1
[submodule "module2"]
    path = module2
    url = https://github.com/<my-org>/module2
    tag = v0.0.1

After cloning / init, you can checkout the tagged version using (PowerShell/Bash):

git submodule foreach 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.tag)'

Or if you just want to view submodule tags in .gitmodules, without doing a checkout:

git submodule foreach 'git config -f $toplevel/.gitmodules submodule.$name.tag'

Lastly, use the tag from .gitmodules OR default to latest tag if none found in .gitmodules:

git submodule foreach 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.tag || git describe --tags $(git rev-list --tags --max-count=1))'

Note these commands will fail when run from cmd.exe! Use Powershell or bash.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文