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

前端 未结 12 1224
旧巷少年郎
旧巷少年郎 2020-11-21 06:39

How does git submodule add -b work?

After adding a submodule with a specific branch, a new cloned repository (after git submodule update --init

相关标签:
12条回答
  • 2020-11-21 06:40

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

    0 讨论(0)
  • 2020-11-21 06:41

    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.

    0 讨论(0)
  • 2020-11-21 06:49

    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 = 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-"
    
    0 讨论(0)
  • 2020-11-21 06:53

    (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 master branch already exist:
          git branch -u origin/master master
      

             (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 
      

    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.

    0 讨论(0)
  • 2020-11-21 06:57

    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.

    0 讨论(0)
  • 2020-11-21 06:57

    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.

    0 讨论(0)
提交回复
热议问题