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

巴特·博格

我正在寻找一种具有git结构(可能嵌套子模块)的情况。对于这些子模块中的每个子模块,我想分别指定它们是否应跟踪分支(例如,参见Git子模块:指定一个分支/标签)。

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

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起作用,但对其余子模块却做错了。

有没有办法很好地做到这一点?

针对第一个答案,我将澄清“做错事情”的意思。

这是一个小例子

[email protected] ~/Desktop/test $ git init
Initialized empty Git repository in /home/bartb/Desktop/test/.git/
[email protected] ~/Desktop/test $ git submodule add ../remote/ submod1
Cloning into 'submod1'...
done.
[email protected] ~/Desktop/test $ git submodule add ../remote/ submod2
Cloning into 'submod2'...
done.
[email protected] ~/Desktop/test $ cd submod1
[email protected] ~/Desktop/test/submod1 $ git log
commit 42d476962fc4e25c64ff2a807d2bf9b3e2ea31f8
Author: Bart Bogaerts <[email protected]>
Date:   Tue Jun 21 08:56:05 2016 +0300

    init commit

commit db1ba3bc4b02df4677f1197dc137ff36ddfeeb5f
Author: Bart Bogaerts <[email protected]>
Date:   Tue Jun 21 08:55:52 2016 +0300

    init commit
[email protected] ~/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
[email protected] ~/Desktop/test/submod1 $ cd ..
[email protected] ~/Desktop/test $ git config -f .gitmodules submodule.submod2.branch master
[email protected] ~/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
[email protected] ~/Desktop/test $ git status
On branch master
nothing to commit, working directory clean
[email protected] ~/Desktop/test $  git submodule update --recursive --remote
Submodule path 'submod1': checked out '42d476962fc4e25c64ff2a807d2bf9b3e2ea31f8'
[email protected] ~/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即使我从未为其配置master分支,也可以在master上检出最新的submod1之后我的意思是“做错事”

子子模块也发生同样的事情:它们都是在主节点而不是在特定的提交时检出的。

这个“问题”实际上是预期的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

这就是我要避免的。

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

VonC

2020年更新:

OP BartBog报告中评论

当前(2016)的答案在子子模块上不能很好地工作(不再吗?),因为$top/.gitmodules它不包含子子模块(和子子子模块)的分支信息。

新解决方案:

export top=$(pwd) 
git submodule foreach 'b=$(git config -f ${top}/.gitmodules submodule.${path}.branch); \
  case "${b}" in \
    "") git checkout ${sha1}; git su ;; 
    *) git checkout ${b}; git pull origin ${b}; git su;; 
  esac')

这里git-su是我的脚本的名称


2016年原始答案:

会将所有子模块更新到关联的分支(默认情况下为master),即它将对submod1和submod2起作用,但对其余子模块却做错了。

实际上,是的,它将做“其余的事情”。

我将在下面的示例中使用git版本2.9.0.windows.1。来说明该错误(一个parent带有子模块' sub'的存储库,本身带有一个子模块' subsub')。

而且,我将提出一个允许sub遵循的简单解决方法master,同时确保subsub自己不会被检出master


设置

让我们subsub通过两个提交进行回购

[email protected] 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'的子模块

[email protected] 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'在其自己的masterHEAD处签出glgit log漂亮格式的别名):

[email protected] 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签出c1不是 master HEAD C2):

[email protected] 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 c1sub

[email protected] D:\git\tests\subm\sub\subsub
> cd ..
[email protected] 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'中添加几个提交

[email protected] 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

[email protected] 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一个子子)

[email protected] 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添加为子模块:

[email protected] D:\git\tests\subm
> git init parent
Initialized empty Git repository in D:/git/tests/subm/parent/.git/
> cd parent

[email protected] D:\git\tests\subm\parent
> git submodule add -- ../sub
Cloning into 'D:/git/tests/subm/parent/sub'...
done.

让我们确保sub不是在其签出masterHEAD(就像我们之前subsub

[email protected] D:\git\tests\subm\parent
> cd sub

[email protected] 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

[email protected] 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提交时签出,而不是在c2 masterHEAD签出parent

[email protected] 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


[email protected] 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

[email protected] 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

[email protected] D:\git\tests\subm\parent
> git add .
> git commit -m "sub follows master"
[master 2310a02] sub follows master
 1 file changed, 1 insertion(+)

[email protected] 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分支(而只sub应签mastersubsub应保持在c1

首先克隆:

[email protected] 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'

到目前为止,一切都很好:subsubsub在被检查出来c1不是 c2(即:不是他们的master HEAD c2

但:

[email protected] 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

而且,即使这样submaster按预期检查),仍然subsub位于c2

[email protected] D:\git\tests\subm\p1\sub
> git ls-tree @
100644 blob 25a0feba7e1c1795be3b8e7869aaa5dba29d33e8    .gitmodules
160000 commit f3087a9bc9b743625e0799f57c017c82c50e35d6  subsub

解决方法:

在不修改suband的任何内容的情况下subsub,这是如何确保subsub保持其预期的c1提交而不是遵循mastersub应该如此)的方式

git submodule update --recursive从本身具有嵌套子模块的子模块进行调用(因此--remote此处不存在

[email protected] D:\git\tests\subm\p1\sub
> git submodule update --recursive
Submodule path 'subsub': checked out 'f3087a9bc9b743625e0799f57c017c82c50e35d6'

现在,我们有:

  • sub保留在master(由于父.gitmodules branch指令及其初始git submodule update --recursive --remote
  • subsub设置回其记录的sha1(c1,not master c2

结论

  1. 它看起来像一个糟糕的设计:--recursive应用--remote所有没有嵌套时,子模块,默认为主submodule.<path>.<branch>发现。
  2. 您可以编写脚本以实现以下目的:
  • update --remote 你想要什么
  • 将顶部父回购.gitmodules文件中未指定分支的任何子模块重置为其正确的SHA1。

只需%PATH%git-subupd脚本中的任意位置创建一个bash脚本,该脚本即使在常规WindowsCMD会话中也可以运行,因为它将由git bash解释。

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命令的组合”简化为一个git调用:

cd /path/to/parent/repo
git subupd

这就对了。
(任何调用的脚本git-xxx都可以由git使用调用git xxx

[email protected] 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(commit c2,未更改),而subsub重置为c1(而不是master c2)。

OP BartBog声明在评论中使用脚本的一个微小的变化:

export top=$(pwd)
git submodule foreach --recursive \
  'b=$(git config -f ${top}/.gitmodules submodule.${path}.branch); \
   case "${b}" in \
     "") git checkout ${sha1};; \
      *) git checkout ${b}; git pull origin ${b};; \
   esac' 

为了避免调用submodule update --remoteAND来确保我的子模块没有处于分离的头部状态(遵循您的回答)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章