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

在添加Git子模块时,如何指定分支/标记?,git,git-submodules,Git,Git Submodules,git子模块add-b是如何工作的 添加具有特定分支的子模块后,新克隆的存储库(在git submodule update--init之后)将处于特定提交状态,而不是分支本身(子模块上的git status显示“当前不在任何分支上”) 我在.gitmodules或.git/config上找不到关于子模块的分支或任何特定提交的任何信息,那么git是如何理解的呢 另外,是否可以指定标记而不是分支 我使用的是1.6.5.2版。Git子模块有点奇怪-它们总是处于“分离头”模式-它们不会像您预期的那样更新

git子模块add-b
是如何工作的

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

我在
.gitmodules
.git/config
上找不到关于子模块的分支或任何特定提交的任何信息,那么git是如何理解的呢

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


我使用的是1.6.5.2版。

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

不过,仔细想想,这确实是有道理的。假设我使用子模块栏创建了存储库foo。我推送我的更改并告诉您从存储库foo签出commit a7402be

然后想象有人在您创建克隆之前提交了对存储库栏的更改

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


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

注意: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
然后,另一个希望将子模块_目录更改为该标记的开发人员执行此操作

git pull
git submodule update --init

git pull
提交子模块目录指向的更改
git子模块更新
实际上合并到新代码中。

我如何使用git子模块的示例

  • 创建一个新的存储库
  • 然后将另一个存储库克隆为子模块
  • 然后我们让子模块使用一个名为V3.1.2的标记
  • 然后我们承诺
  • 这看起来有点像这样:

    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 
    
    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
        branch = master
    

    也许这会有帮助(即使我使用的是标记而不是分支)

    Git1.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子模块

  • 您的
    .gitmodules
    有如下条目:

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

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

    现在,
    -b
    所做的就是在
    .gitmodules
    文件中添加一行。因此,按照相同的示例,它将如下所示:

    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 
    
    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
        branch = master
    
    注意:
    .gitmodules
    文件中只支持分支名称,但不支持SHA和标记(相反,可以使用“
    git add.
    ”跟踪和更新分支对每个模块的提交,例如
    git add./SubmoduleTestRepo
    ,并且您不需要每次更改
    .gitmodules
    文件)

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

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

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

  • (已推出2019年第2季度Git 2.22)

    请注意,如果现有子模块尚未跟踪分支,则():

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

        cd /path/to/your/parent/repo
        git config -f .gitmodules submodule.<path>.branch <branch>
      
          git submodule update --recursive --remote
      
    (使用“origin”作为子模块的名称,子模块已从中克隆。
             该子模块内的一个
    git remote-v
    将显示它。通常,它是“origin”)

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

        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 
      

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

    分支的名称在
    .gitmodule中记录为
    子模块..branch
     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' –
      
    
    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)'
    
    [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-"
    
    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']
    
    $ quack