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

Iva*_*van 698 git git-submodules

git submodule add -b工作怎么样?

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

我无法找到任何信息.gitmodules.git/config关于子模块的分支或任何具体的承诺,那么,如何Git的数字出来?

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

我正在使用1.6.5.2版.

dja*_*bs7 703

注意: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
Run Code Online (Sandbox Code Playgroud)

然后,另一个想要将submodule_directory更改为该标记的开发人员执行此操作

git pull
git submodule update --init
Run Code Online (Sandbox Code Playgroud)

git pull提交其子模块目录的更改. git submodule update实际上合并在新代码中.

  • `git checkout v1.0`是分支还是标签? (10认同)
  • 这是一个非常好的解释,谢谢!当然,在阅读完答案之后,我意识到提交被保存在子模块本身(子模块/ .git/HEAD)中. (8认同)
  • 将标记视为提交的人类可读别名.提交是每个文件的一组特定状态.分支基本上是相同的,除了你可以对它进行更改. (7认同)
  • 这似乎不适用于git 1.7.4.4.`cd my_submodule; git checkout [子模块的存储库中的ref`产生`致命:引用不是树:...`.好像`git`只能在父存储库上运行. (4认同)
  • 即使对于经常更新的项目,使用git子模块也是很好的.Linux内核使用它并没有那么糟糕 (3认同)
  • 注意:遥控器必须采用git://的形式,使用http会导致失败。我花了一段时间才意识到我没有使用正确的协议。 (2认同)
  • 谢谢您的回答,但是没有用。它没有将文件夹添加到要提交的更改中。 (2认同)

Joh*_*y Z 591

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

当你有这两件事时,你知道你有一个Git子模块.

  1. .gitmodules有这样的条目:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您的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
    
    Run Code Online (Sandbox Code Playgroud)

    编辑:上面只支持分支名称,而不是SHA或TAG.

    子模块对象仍指向特定的提交.根据Vogella的回答,该.gitmodules选项购买的唯一功能是能够git add .为您的更新添加标记:

    git submodule update --remote
    
    Run Code Online (Sandbox Code Playgroud)

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

    git add ./SubmoduleTestRepo并不是一些神奇的方法来保持一切与分支最新.它只是添加有关.gitmodules文件中某个分支的信息,并为您提供了在填充之前将子模块对象更新为指定分支的最新提交的选项.

  • 这个答案是唯一对我有意义的答案.谢谢. (63认同)
  • 这个答案应该有更多的选票.过去一天我一直在阅读很多帖子,这清除了所有的困惑.来自SVN世界并使用外部 - 人们想要相信git子模块分支跟踪可以神奇地保持所有最新的分支 - 但事实并非如此!你必须明确更新它们!如您所述,您必须提交已更改的子模块对象. (10认同)
  • 此分支跟踪是否也适用于**标签**?而不是我在`.gitmodules`中指定了一个标签,并且在执行`$ git submodule update --init --remote TestModule`之后,我收到一个错误,说'致命:需要一个修订版'和`无法找到当前来源子模块路径'TestModule'中的/ TestTag修订版.使用真正的分支时,它可以工作.无论如何在`.gitmodules`中指定一个标签而不必指定确切的提交? (10认同)
  • 这似乎不起作用.我更新了`.gitmodules`中的哈希并运行了`git submodule update`而没有发生任何事情? (5认同)
  • tldr:锁定标签:cd 进入该子模块,签出标签;犯罪。 (3认同)
  • @JohnnyZ,您提到要跟踪的特定提交的信息来自 .gitmodules 文件。但我认为提交的 SHA 实际上来自 `.git/modules/<submodule_name>/HEAD` IIRC。 (2认同)
  • @CMCDragonkai:您必须通过执行 git submodulesync 来同步 url,以使更改生效。 (2认同)
  • 不知怎的,这对我不起作用.使用SHA Commit Id,我总是收到错误"无法找到当前版本(我仔细检查了HEAD的修订版号及其正确).但是如果我使用master它可以工作. (2认同)
  • 在分支属性中输入 SHA 对我也不起作用。文档也*不*支持这种用法:https://git-scm.com/docs/gitmodules (2认同)
  • 几乎完美......但是你的'-b'是指什么?上一个答案中的哪个 git 命令使用了 -b? (2认同)
  • 我认为这可能有点令人困惑,并可能导致人们尝试向 `.gitmodules` 添加 SHA1 值:“_每当您执行 git 子模块更新时......它知道在哪里可以找到提交,因为其中的信息.gitmodules._”(如同一答案中所述)`.gitmodules` 文件没有为子模块提供 **commit**。实际提交(SHA1)不在“.gitmodules”文件中,而是在包含存储库的“.git/modules/”文件夹中(此处为“.git/modules/SubmoduleTestRepo/”)。更多详细信息:/sf/ask/763981571/。[啊,@Sid已经说过了。] (2认同)

Von*_*onC 310

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

  • 确保父repo知道它的子模块现在跟踪一个分支:

    cd /path/to/your/parent/repo
    git config -f .gitmodules submodule.<path>.branch <branch>
    
    Run Code Online (Sandbox Code Playgroud)
  • 确保您的子模块实际上是该分支的最新部分:

    cd path/to/your/submodule
    git checkout -b branch --track origin/branch
      # if the master branch already exist:
      git branch -u origin/master master
    
    Run Code Online (Sandbox Code Playgroud)

         (与"原点"是的名称上游远程回购子模块已从.克隆
         甲git submodule set-branch --branch aBranch -- <submodule_path>内部的子模块将其显示.通常,它是"原点")

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

    cd /path/to/your/parent/repo
    git add path/to/your/submodule
    git commit -m "Make submodule tracking a branch"
    
    Run Code Online (Sandbox Code Playgroud)
  • 该子模块的后续更新必须使用以下git remote -v选项:

    # 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 
    
    Run Code Online (Sandbox Code Playgroud)

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

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


如果要更新分支后的所有子模块:

    git submodule update --recursive --remote
Run Code Online (Sandbox Code Playgroud)

请注意,对于每个更新的子模块,结果几乎总是一个独立的HEAD,正如Dan Cameron他的回答中所说.

(Clintm notes in the comments that, if you run . 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 checkout $branch'
Run Code Online (Sandbox Code Playgroud)

每个子模块仍将引用相同的SHA1,但是如果您确实进行了新的提交,则可以推送它们,因为它们将由您希望子模块跟踪的分支引用.
在子模块中推送之后,不要忘记返回到父repo,添加,提交并推送新的SHA1用于那些已修改的子模块.

使用注意事项git submodule update --remote,建议在评论亚历山大Pogrebnyak.
$toplevel于2010年5月在git1.7.2中引入:提交f030c96.

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

.gitmodules在评论中添加:

foreach脚本将无法签出不在分支之后的子模块.
但是,此命令为您提供:

 git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch' –
Run Code Online (Sandbox Code Playgroud)

相同的命令,但更容易阅读:

git submodule foreach -q --recursive \
    'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
     [ "$branch" = "" ] && \
     git checkout master || git checkout $branch' –
Run Code Online (Sandbox Code Playgroud)

umläute 在评论中用简化版改进了dtmland的命令:

git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
Run Code Online (Sandbox Code Playgroud)

多行:

git submodule foreach -q --recursive \
  'git checkout \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
Run Code Online (Sandbox Code Playgroud)

  • 问题:如果我有文件夹 subModule1 并希望跟踪 master 分支,结果命令是否如下所示:**git config -f .gitmodules submodule.subModule1.branch master** (2认同)
  • 这是@dtmland脚本的简化版:`git submodule foreach -q --recursive'git checkout $(git config -f $ toplevel/.gitmodules submodule.$ name.branch || echo master)'` (2认同)

vog*_*lla 193

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 
Run Code Online (Sandbox Code Playgroud)

另请参见Git子模块

  • @KCD哪个版本的git可以用标签做到这一点.我的不行? (7认同)
  • 这也适用于标签吗? (4认同)
  • 谢谢,我刚刚使用有关信息来帮助我创建一个与 GitHub gh-pages 网站同步的子模块文件夹:完整示例位于 https://github.com/o2platform/ Fluentnode/issues/22 (2认同)
  • 您可以使用`git submodule add -b tags/<sometag> <url>`锁定到*标签*,您可以在`.gitmodules中看到`branch = tags/<sometag>`行 (2认同)

Joh*_*han 53

我如何使用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 
Run Code Online (Sandbox Code Playgroud)

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

  • 这与djacobs7的答案基本相同,但无论如何,谢谢:) (4认同)

Dmi*_*kiy 53

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

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

  1. 编辑真相来源.gitmodules

例如,从

[submodule "api"]
    path = api
    url = https://github.com/<original_repo>/api.git
Run Code Online (Sandbox Code Playgroud)

[submodule "api"]
    path = api
    url = https://github.com/<another_repo>/api.git
    branch = work-in-progress
Run Code Online (Sandbox Code Playgroud)

您还可以用于hexsha提交哈希。或者tag,但参见 3。

  1. git submodule sync.git/modules:根据 中指定的刚刚编辑的真实来源更新 git 缓存的子模块的描述.gitmodules

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

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

  4. 提交更改。


小智 37

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

而不是手动或通过脚本手动检出正确的分支git子模块foreach可以使用.

这将检查分支属性的子模块配置文件并检查set分支.

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


Nea*_*all 32

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

不过,当你考虑它时,这确实有些意义.假设我使用子模块创建存储库foo.我推动我的更改,并告诉你检查从存储库foo提交a7402be .

然后想象有人在您进行克隆之前将更改提交到存储库.

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

我个人认为子模块是Git最容易混淆的部分.有很多地方可以比我更好地解释子模块.我推荐Scott Chacon的Pro Git.

  • 问题是应该有一个选项来说"将这个子模块保留在分支X上",这样如果你想让它自动更新,那么你可以做到这一点.这将使子模块更有用于管理例如WordPress安装,其中插件都是Git repos,而不必为每个更新的插件重新保存超级项目. (6认同)
  • 关于 Git 最令人困惑的部分是,即使经过十多年的开发,一个旨在帮助我完成工作的工具仍然具有如此糟糕的用户体验,而且出于完全超出我的原因,人们喜欢被 Git 指指点点时间。 (2认同)

Eng*_*eer 17

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

  • cd 到包含子模块的存储库的根目录
  • 打开.gitmodules进行编辑
  • 加入线下path = ...url = ...,说branch = your-branch,对每个子模块; 保存文件.gitmodules.
  • 那么不用改变目录呢 $ git submodule update --remote

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


Pas*_* T. 9

我在.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-"
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

461725 次

最近记录:

6 年,3 月 前