Search code examples
gitgit-submodules

Update/sync all repo to the specific commit in submodule


I have repo structured in the following way:

|- project/
|  |- tools/
|  |- toolchain/
|     |- linux/
|     |- windows/
|  |- code/
|  |- shared/
|   

Where tools, code and shared are submodules. Also /toolchain/linux and /toolchain/windows are submodules too.

The problem is I want to switch in code for a specific commit. To build my code I need to sync all other submodules with that commit (let's say toolchain for linux was updated and I can't build old code with latest toolchain). How to do it in git?


Solution

  • You need to find the corresponding commit in the superproject project and check it out; it then will recursively check out all submodules to their stored commits.

    The following code requires Unix tools (sh, xargs, awk).

    This pipeline

    git rev-list @ code/ |
    xargs -I @ sh -c "echo -n '@ '; git rev-parse @:code"
    

    prints a list of pairs of commits IDs: a commit from the superproject where the submodule was changed, and the commit of the submodule. Filter it by the required commit in the submodule and print the commit from the project:

    git rev-list @ code/ |
    xargs -I @ sh -c "echo -n '@ '; git rev-parse @:code" |
    awk '$2=="$commitID_from_code" {print $1}'
    

    Now let's automate checkout:

    git rev-list @ code/ |
    xargs -I @ sh -c "echo -n '@ '; git rev-parse @:code" |
    awk '$2=="$commitID_from_code" {print $1}' |
    xargs -r git checkout --recurse-submodules
    

    Or git switch --detach --recurse-submodules instead of git checkout.

    Will do nothing if the pipeline didn't find the specified commit.