Git:在子模块中跟踪分支但在其他子模块中提交(可能是嵌套的)

时间:2016-06-17 10:49:49

标签: git git-branch git-submodules

我正在寻找一种情况,其中我有一个git结构(可能是嵌套的子模块)。对于这些子模块中的每一个,我想单独指定它们是否应该跟踪分支 (参见例如Git submodules: Specify a branch/tag

例如,我的项目可能如下所示:

main.tex
|- submod1 @ master
|    |-subsubmod1 @qsdf123
|- submod2 @ master
|    |-subsubmod2 @shasha12
|- submod3 @ qsdf321

现在,我想要一种更新子模块的方法。

git submodule update --recursive

将所有子模块更新为其最后记录的sha(即,它将适用于subsubmod1,subsubmod2和submod3,但其余部分则执行错误操作。 另一方面

git submodule update --recursive --remote

会将所有子模块更新到关联的分支(默认情况下为master),也就是说,它将适用于submod1和submod2,但其余部分会执行错误的操作。

有没有办法很好地完成这项工作?

在回答第一个答案时,我会澄清“做错事”的意思。

这是一个小例子

bartb@EB-Latitude-E5450 ~/Desktop/test $ git init
Initialized empty Git repository in /home/bartb/Desktop/test/.git/
bartb@EB-Latitude-E5450 ~/Desktop/test $ git submodule add ../remote/ submod1
Cloning into 'submod1'...
done.
bartb@EB-Latitude-E5450 ~/Desktop/test $ git submodule add ../remote/ submod2
Cloning into 'submod2'...
done.
bartb@EB-Latitude-E5450 ~/Desktop/test $ cd submod1
bartb@EB-Latitude-E5450 ~/Desktop/test/submod1 $ git log
commit 42d476962fc4e25c64ff2a807d2bf9b3e2ea31f8
Author: Bart Bogaerts <bart.bogaerts@cs.kuleuven.be>
Date:   Tue Jun 21 08:56:05 2016 +0300

    init commit

commit db1ba3bc4b02df4677f1197dc137ff36ddfeeb5f
Author: Bart Bogaerts <bart.bogaerts@cs.kuleuven.be>
Date:   Tue Jun 21 08:55:52 2016 +0300

    init commit
bartb@EB-Latitude-E5450 ~/Desktop/test/submod1 $ git checkout db1ba3bc4b02df4677f1197dc137ff36ddfeeb5f
Note: checking out 'db1ba3bc4b02df4677f1197dc137ff36ddfeeb5f'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at db1ba3b... init commit
bartb@EB-Latitude-E5450 ~/Desktop/test/submod1 $ cd ..
bartb@EB-Latitude-E5450 ~/Desktop/test $ git config -f .gitmodules submodule.submod2.branch master
bartb@EB-Latitude-E5450 ~/Desktop/test $ git commit -a -m "modules"
[master (root-commit) ea9e55f] modules
 3 files changed, 9 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 submod1
 create mode 160000 submod2
bartb@EB-Latitude-E5450 ~/Desktop/test $ git status
On branch master
nothing to commit, working directory clean
bartb@EB-Latitude-E5450 ~/Desktop/test $  git submodule update --recursive --remote
Submodule path 'submod1': checked out '42d476962fc4e25c64ff2a807d2bf9b3e2ea31f8'
bartb@EB-Latitude-E5450 ~/Desktop/test $ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   submod1 (new commits)

正如您所看到的,在主服务器上检出最新的git submodule update --remote submod1之后,即使我从未为其配置主分支。这就是我所说的“做错事”

子子模块也会发生同样的事情:它们都是在master处检出的,而不是在特定的提交中检出的。

这个“问题”实际上是git submodule update --remote的预期。来自git文档:

This option is only valid for the update command. Instead of using the superproject’s recorded SHA-1 to update the submodule, use the status of the submodule’s remote-tracking branch. The remote used is branch’s remote (branch.<name>.remote), defaulting to origin. The remote branch used defaults to master, but the branch name may be overridden by setting the submodule.<name>.branch option in either .gitmodules or .git/config (with .git/config taking precedence).

https://git-scm.com/docs/git-submodule

特别是部分:

The remote branch used defaults to master

这是我想要避免的。

编辑:另一个请求是:我不想对submods或subsubmods进行任何修改(这些是联合项目)。

1 个答案:

答案 0 :(得分:2)

  

会将所有子模块更新到关联的分支(默认情况下为master),也就是说,它将适用于submod1和submod2,但其余部分会执行错误的操作。

实际上,是的,它会做“其余的错误的东西”。

我将使用git version 2.9在下面的示例(带有子模块“parent”的副本sub,本身带有子模块“subsub”)中说明该错误。 0.windows.1。

我将提出一个简单的解决方法,允许sub关注master,同时确保subsub不会在自己的master检出。

设置

让我们做一个包含两次提交的回复subsub

vonc@VONCAVN7 D:\git\tests\subm
> git init subsub1
Initialized empty Git repository in D:/git/tests/subm/subsub1/.git/
> cd subsub1
> git commit --allow-empty -m "subsub c1"
[master (root-commit) f3087a9] subsub c1
> git commit --allow-empty -m "subsub c2"
[master 03d08cc] subsub c2

让这个回购subsub成为另一个回购'sub'的子模块:

vonc@VONCAVN7 D:\git\tests\subm
> git init sub
Initialized empty Git repository in D:/git/tests/subm/sub/.git/

> cd sub
> git submodule add -- ../subsub
Cloning into 'D:/git/tests/subm/sub/subsub'...
done.

默认情况下,该子模块“subsub”已在自己的master HEAD(gl is an alias for git log with pretty format)处签出:

vonc@VONCAVN7 D:\git\tests\subm\sub\subsub
> gl
* 03d08cc  - (HEAD -> master, origin/master, origin/HEAD) subsub c2 (4 minutes ago) VonC
* f3087a9  - subsub c1 (4 minutes ago) VonC

让我们确保sub已在subsub({em>不 c1)签出master HEAD C2

vonc@VONCAVN7 D:\git\tests\subm\sub\subsub
> git checkout @~
Note: checking out '@~'.

You are in 'detached HEAD' state.     
HEAD is now at f3087a9... subsub c1
> git br -avv
* (HEAD detached at f3087a9) f3087a9 subsub c1
  master                03d08cc [origin/master] subsub c2
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master 03d08cc subsub c2

让我们在其父代表“subsub”中添加并提交该子模块“master~1”(在c1 sub处签出):

vonc@VONCAVN7 D:\git\tests\subm\sub\subsub
> cd ..
vonc@VONCAVN7 D:\git\tests\subm\sub
> git add .
> git commit -m "subsub at HEAD-1"
[master (root-commit) 1b8144b] subsub at HEAD-1
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 subsub

让我们在回购邮件'sub'中添加几个提交:

vonc@VONCAVN7 D:\git\tests\subm\sub
> git commit --allow-empty -m "sub c1"
[master b7d1c40] sub c1
> git commit --allow-empty -m "sub c2"
[master c77f4b2] sub c2

vonc@VONCAVN7 D:\git\tests\subm\sub
> gl
* c77f4b2  - (HEAD -> master) sub c2 (2 seconds ago) VonC
* b7d1c40  - sub c1 (3 seconds ago) VonC
* 1b8144b  - subsub at HEAD-1 (77 seconds ago) VonC

sub的最新提交确实在正确的提交中引用了其子模块“subsub”(子文档c1,而不是c2

vonc@VONCAVN7 D:\git\tests\subm\sub
> git ls-tree @
100644 blob 25a0feba7e1c1795be3b8e7869aaa5dba29d33e8    .gitmodules
160000 commit f3087a9bc9b743625e0799f57c017c82c50e35d6  subsub
              ^^^
              That is subsub master~1 commit c1

最后,让我们制作一个主要的父回购'parent'并添加'sub'作为子模块:

vonc@VONCAVN7 D:\git\tests\subm
> git init parent
Initialized empty Git repository in D:/git/tests/subm/parent/.git/
> cd parent

vonc@VONCAVN7 D:\git\tests\subm\parent
> git submodule add -- ../sub
Cloning into 'D:/git/tests/subm/parent/sub'...
done.

让我们确保sub <{1}} HEAD(就像我们之前为master所做的那样)

subsub

现在,我们将vonc@VONCAVN7 D:\git\tests\subm\parent > cd sub vonc@VONCAVN7 D:\git\tests\subm\parent\sub > gl * c77f4b2 - (HEAD -> master, origin/master, origin/HEAD) sub c2 (2 minutes ago) VonC * b7d1c40 - sub c1 (2 minutes ago) VonC * 1b8144b - subsub at HEAD-1 (3 minutes ago) VonC vonc@VONCAVN7 D:\git\tests\subm\parent\sub > git checkout @~1 Note: checking out '@~1'. You are in 'detached HEAD' state. HEAD is now at b7d1c40... sub c1 (在其sub提交处检出,而不是在其c1 HEAD处)添加到c2 master回购:

parent

让我们vonc@VONCAVN7 D:\git\tests\subm\parent > git add . > git st On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: .gitmodules new file: sub vonc@VONCAVN7 D:\git\tests\subm\parent > git commit -m "sub at c1" [master (root-commit) 27374ec] sub at c1 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 sub 跟随sub作为回购master中的子模块:

parent

BUG:

如果我克隆了回购vonc@VONCAVN7 D:\git\tests\subm\parent > git config -f .gitmodules submodule.sub.branch master > git diff diff --git a/.gitmodules b/.gitmodules index 8688a8c..97974c1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "sub"] path = sub url = ../sub + branch = master vonc@VONCAVN7 D:\git\tests\subm\parent > git add . > git commit -m "sub follows master" [master 2310a02] sub follows master 1 file changed, 1 insertion(+) vonc@VONCAVN7 D:\git\tests\subm\parent > gl * 2310a02 - (HEAD -> master) sub follows master (1 second ago) VonC * 27374ec - sub at c1 (2 minutes ago) VonC ,然后要求其任何子模块在其远程分支后结帐,parent sub 将结帐他们的subsub分支(只有master结帐submaster应该保留在subsub

首先是克隆:

c1

到目前为止,非常好:vonc@VONCAVN7 D:\git\tests\subm > git clone --recursive parent p1 Cloning into 'p1'... done. Submodule 'sub' (D:/git/tests/subm/sub) registered for path 'sub' Cloning into 'D:/git/tests/subm/p1/sub'... done. Submodule path 'sub': checked out 'b7d1c403edaddf6a4c00bbbaa8e2dfa6ffbd112f' Submodule 'subsub' (D:/git/tests/subm/subsub) registered for path 'sub/subsub' Cloning into 'D:/git/tests/subm/p1/sub/subsub'... done. Submodule path 'sub/subsub': checked out 'f3087a9bc9b743625e0799f57c017c82c50e35d6' sub已在subsub而非 c1签出(即:不是他们的{ {1}})

但是:

c2

现在,从克隆master HEAD c2开始,子模块和子模块都位于vonc@VONCAVN7 D:\git\tests\subm\p1 > git submodule update --recursive --remote Submodule path 'sub': checked out 'c77f4b2590794e030ec68a8cea23ae566701d2de' Submodule path 'sub/subsub': checked out '03d08cc81e3b9c0734b8f53fad03ea7b1f0373df'

即便如此,p1(按预期master HEAD c2检查)仍然sub位于master

subsub

解决方法:

不修改c2vonc@VONCAVN7 D:\git\tests\subm\p1\sub > git ls-tree @ 100644 blob 25a0feba7e1c1795be3b8e7869aaa5dba29d33e8 .gitmodules 160000 commit f3087a9bc9b743625e0799f57c017c82c50e35d6 subsub 中的任何内容,以下是如何确保sub保留在其预期的subsub提交中,而不是关注subsub(如c1应该是)

从子模块中调用master,子模块本身嵌套了子模块(这里没有sub

git submodule update --recursive

我们现在有:

  • --remote留在vonc@VONCAVN7 D:\git\tests\subm\p1\sub > git submodule update --recursive Submodule path 'subsub': checked out 'f3087a9bc9b743625e0799f57c017c82c50e35d6' (由于父sub master指令及其初始.gitmodules
  • branch被设置回其记录的sha1(git submodule update --recursive --remote,而非subsub

结论

  1. 看起来确实是一个糟糕的设计:c1master c2应用于所有嵌套的子模块,当找不到--recursive时默认为master。
  2. 您可以通过以下方式编写脚本:

    • --remote你想要什么
    • 将顶级父repo submodule.<path>.<branch>文件中未指定分支的任何子模块重置为正确的SHA1。
  3. 只需在update --remote .gitmodules脚本中创建任意位置(bash脚本,即使在常规Windows %PATH%会话中也可以使用,因为它将由git bash解释)

    git-subupd

    CMD

    “git命令的组合”减少到一个git调用:

    git-subupd

    就是这样 (任何名为#!/bin/bash git submodule update --recursive --remote export top=$(pwd) git submodule foreach --recursive 'b=$(git config -f ${top}/.gitmodules submodule.${path}.branch); case "${b}" in "") git checkout ${sha1};; esac' 的脚本都可以通过git使用cd /path/to/parent/repo git subupd

    调用
    git-xxx

    git xxx仍然设置为vonc@VONCAVN7 D:\git\tests\subm\p1 > git subupd Submodule path 'sub/subsub': checked out '03d08cc81e3b9c0734b8f53fad03ea7b1f0373df' Entering 'sub' Entering 'sub/subsub' Previous HEAD position was 03d08cc... subsub c2 HEAD is now at f3087a9... subsub c1 (提交sub,未更改),而master重置为c2(而不是subsub )。

    OP BartBog使用该脚本的略微变体声明in the comments

    c1
      

    避免调用master c2并确保我的子模块不处于分离头状态(符合your answer)。