【问题标题】:git submodule replacement that doesn't detach heads不分离头的git子模块替换
【发布时间】:2022-01-07 23:45:01
【问题描述】:

我的情况:我有大量用于各种任务的计算机。我有大量的库,每个库都有自己的 git repo。

我的愿望:我希望能够在任何计算机上修改其中一个库,执行 git commit/push;然后转到另一台计算机,执行git pull,并更新所有库。然后我修改其中一个库,提交/推送,当我到达下一台计算机时一切正常。

我目前的尝试:我有一个顶级 git 项目,它将所有其他库 repos 合并为子模块。这包括一个 .gitmodules 文件,该文件通过使用指定每个模块的工作分支

git config -f .gitmodules submodule.modulename.branch develop

我为每个模块设置了update = merge。 我将submodule.recurse 设置为true,所以顶层的git pull 对每个模块执行某些操作

如何损坏:头部脱落。我编写了一个脚本来解析.gitmodules 文件并对每个模块的相应分支执行checkout。然后我 commitpush 顶部模块。每当我修改东西并尝试拉动时,例如在另一台机器上,磁头分离。如果我在开始修改之前没有注意到头部已分离,我必须在提交更改之前仔细整理残骸。

在过去的十年里,实际上有 3.6k 的关于 git 分离头的堆栈溢出问题,而且大多数似乎来自子模块功能。我还没有完成所有这些,但是我尝试过的方法不起作用。

我忘记了为什么我拒绝了 git-subtree,但是 git-subrepo 已经一年多没有被触及,并且有 153 个问题和 25 个拉取请求待处理,所以我认为它已经死了。

有人对此有有效的解决方案吗?


@vonC 接受的答案看起来不错。

我可能会稍微简化一下,但我的顶级项目自述文件现在说:

推荐结帐:

git clone --recursive --jobs=8 *mysuperproject_clone_url*
cd *mysuperproject*
git config alias.pullall 'submodule foreach git pull'
git config alias.statusall 'submodule foreach git status'
git config alias.switchall \
    "submodule foreach --recursive 'git switch \$(git config -f \${toplevel}/.gitmodules submodule.\${sm_path}.branch)'"
git switchall

从存储库更新

git pullall

如果磁头脱落,用

修复
git switchall

添加模块

在以下示例中名为 newmodule 的模块在路径 develop 上工作。

cd /path/to/mysuperproject
git submodule add git@github.com:myaccount/newmodule
git config -f .gitmodules submodule.newmodule.branch develop
git config -f .gitmodules submodule.newmodule.update merge

如果子模块在默认的master 分支上,你仍然需要配置分支。

如果您将子模块切换到不同的分支,则必须在顶层重新配置

git config -f .gitmodules submodule.newmodule.branch newbranch

同时推送子模块和顶层项目。

在不同的工作目录(例如在不同的机器上),您必须

cd /path/to/mysuperproject
git pull
git switchall
git pullall

【问题讨论】:

  • 有一个正在进行的(但可能是遥不可及的)项目来重新设计子模块的“用户体验”(UX),但这确实是它们的用途:作为分离-HEAD 几乎一直在设置。总体思路是在子模块中完全避免使用分支名称,因为此时分支名称具有负函数值。
  • 我的意思很简单:branch name 代表 latest 提交。 Git 中的一个 submodule 代表一个 specific 提交。如果该提交哈希 ID 只是因为某处的某个分支名称发生了更改而更改,那将是不正确的行为。因此,如果子模块留在“分支”上,这将被视为缺陷。这可能是暂时需要的缺陷,但从子模块设计的角度来看,这是一个错误。
  • @torek 所以你说子模块不是我(看似常见的)用例的合适工具。有用的行为是不正确的行为。所以问题是:git中有正确的工具吗?或者可以使用可用的工具来完成这项工作。
  • 据我所知,没有正确的工具。谷歌的人写了repo(Python的东西)来解决这个问题,但似乎已经放弃了repo,所以显然这也有很大的问题。

标签: git git-submodules git-subtree git-detached-head git-subrepo


【解决方案1】:

mentioned before 认为 git submodule update --remote --merge 应该在分支之后分离子模块的 HEAD。

我知道您设置了update = merge,但只是为了测试,请尝试完整的更新命令,看看这是否有效。

由于 HEAD 仍处于分离状态,您需要添加(例如到 git 别名脚本)命令

git submodule foreach --recursive git switch $(git config -f .gitmodules submodule.${sm_path}.branch)

我刚刚测试过:

首先,在 Git 存储库中,我检查子模块是否处于分离的 HEAD 模式:

vonc@vclp MINGW64 ~/git/git (master)
$ git submodule update --init
Submodule 'sha1collisiondetection' (https://github.com/cr-marcstevens/sha1collisiondetection.git) registered for path 'sha1collisiondetection'
Cloning into 'C:/Users/vonc/git/git/sha1collisiondetection'...
Submodule path 'sha1collisiondetection': checked out '855827c583bc30645ba427885caa40c5b81764d2'


vonc@vclp MINGW64 ~/git/git/sha1collisiondetection (master)
$ git br
* (HEAD detached at 855827c)
  master

然后我定义我的别名,转义 $: \$
访问.gitmodules 文件时不需要../。这就是$toplevel 的用途。

vonc@vclp MINGW64 ~/git/git (master)
$ git config alias.switchall \
    "submodule foreach --recursive 'git switch \$(git config -f \${toplevel}/.gitmodules submodule.\${sm_path}.branch)'"

最终测试:

vonc@vclp MINGW64 ~/git/git (master)
$ git switchall
Entering 'sha1collisiondetection'
Previous HEAD position was 855827c Detect endianess on HP-UX
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

vonc@vclp MINGW64 ~/git/git (tmp)
$ cd sha1collisiondetection/

vonc@vclp MINGW64 ~/git/git/sha1collisiondetection (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

vonc@vclp MINGW64 ~/git/git/sha1collisiondetection (master)
$ git branch
* master

【讨论】:

  • 编辑问题的答案
  • @DMPalmer 好的。我已经编辑了答案以提出解决方案。
  • 我将如何以及何时执行此操作?我可以在 git 中添加一个“钩子”,这样每次我做任何事情时它都会重新连接所有的头吗?
  • @DMPalmer 你可以定义一个 git 别名函数来链接两个命令:stackoverflow.com/a/7005698/6309
  • 它对我不起作用,因为 ${sm_path} 甚至在 git 启动之前就被我的 bash shell 解释了,或者因为 .gitmodules 不在子模块的目录中,或者两者兼而有之。第二个可以通过使用 ../gitmodules 来修复,但我还没有找到正确的转义模式来修复第二个。别名:switchall = submodule foreach --recursive git switch $(git config -f ../.gitmodules submodule.${sm_path}.branch) 每次都会查看submodule..branch
猜你喜欢
  • 1970-01-01
  • 2014-01-14
  • 2013-09-17
  • 1970-01-01
  • 2010-10-03
  • 2011-09-23
  • 2019-02-13
  • 2015-02-21
  • 1970-01-01
相关资源
最近更新 更多