删除或增加 .gitmodule 中的项目 url 和 commit id

        简单来说,.gitmodules 文件中的 path 配置项就是用来指定将外部仓库关联到本项目中的哪个文件夹的。

        下面我们详细演示操作过程。

1. 核心概念:.gitmodules 文件

        当使用 git submodule add 命令时,Git 会自动创建或修改一个名为 .gitmodules 的文件,它位于 Git 仓库的根目录。这个文件记录了所有子模块的信息。

它的基本结构如下:

[submodule "path/to/your/folder"]
    path = path/to/your/folder
    url = https://github.com/username/repository.git

解释:

[submodule "path/to/your/folder"]  

        这是一个分区标题,通常用子模块在本地的路径来命名,方便识别。

path    

        这是指定关联文件夹的配置项。它的值是外部仓库内容存放到的本项目内的相对路径

url   

        这是子模块(外部仓库)的克隆地址。它可以是 HTTPS 或 SSH 链接。

 

2. 添加一个关联到指定文件夹的子模块

        假设我们的项目结构如下:

my-project/
├── src/
├── docs/
└── README.md

        现在需要将另一个名为 external-lib 的仓库(地址为 https://github.com/someuser/external-lib.git)添加为本项目的子模块,并希望把它放在 libs/external-lib 文件夹里。

2.1.  终端中执行命令

    使用 git submodule add 命令,并在后面指定路径。

# 语法: git submodule add <repository_url> <指定文件夹路径>
git submodule add https://github.com/someuser/external-lib.git libs/external-lib

2.2.  命令的作用

        Git 会从远程拉取 external-lib 仓库的内容。会在主项目的根目录下创建一个 libs/external-lib 文件夹,并将外部仓库的文件 clone 到其中。自动创建或更新 .gitmodules 文件,添加相应的配置。在项目的 .git/config 文件中也会添加子模块的信息。创建一个特殊的 gitlink(可以理解为一个特殊记录)在暂存区,指向刚才拉取的那个子模块的特定提交

2.3.  查看结果

        于是,项目结构现在变成了如下:

my-project/
├── .gitmodules
├── libs/
│   └── external-lib/    # <-- 这就是你指定的文件夹
│       ├── (external-lib 的项目文件)
├── src/
├── docs/
└── README.md

        而 .gitmodules 文件内容会像这样:

[submodule "libs/external-lib"]
    path = libs/external-lib
    url = https://github.com/someuser/external-lib.git

2.4.  提交更改

       最后,需要提交主项目的更改,这将记录子模块的路径和它所指向的提交。

git add .gitmodules libs/external-lib # 或者直接 git add .
git commit -m "feat: add external-lib as a submodule in libs/external-lib folder"

 

3. 注意事项

  1. 路径不能已存在

            指定的文件夹路径(例如 libs/external-lib)在添加子模块之前不能已经是一个被 Git 跟踪的文件夹。它应该是一个全新的路径,或者是一个空的、未跟踪的文件夹。否则命令会失败。

  2. 克隆包含子模块的项目

            当重新克隆主项目时,默认只会克隆主项目,子模块的文件夹是空的。需要多执行两步命令:

    git clone <your-repo-url>
    git submodule init    # 初始化本地配置文件(通常可省略)
    git submodule update  # 从 .gitmodules 中记录的仓库拉取数据到指定路径

            或者:

    git clone <your-repo-url>
    git submodule update --init --recursive

            或者使用组合命令一步到位:

    git clone --recurse-submodules <your-repo-url>
  3. 修改已存在的子模块路径(不常见)

    如果想修改一个已存在子模块的关联路径,步骤会稍微复杂一些:

    • 编辑 .gitmodules 文件,修改 path 的值。

    • 运行 git submodule sync 命令将新的路径同步到主项目的 .git/config 文件中。

    • 手动将子模块的文件夹从旧路径移动到新路径。

    • 提交更改。

    注意: 直接修改 .gitmodules 文件容易出错,建议先删除再重新添加子模块(如果历史不重要的话)。

4. 删除(修改)submodule link

        完全删除一个子模块(包括从 .gitmodules 中删除记录)需要执行一系列步骤,不能简单地只删除 .gitmodules 文件中的一行。如果操作不当,可能会留下残留的配置。

按照以下步骤安全彻底地删除一个子模块。

4.1. 完整删除子模块的步骤

        假设你要删除的子模块在 .gitmodules 中对应的路径是 libs/external-lib

第 1 步:删除子模块的注册条目

        使用 git submodule deinit 命令来注销子模块,这会从 .git/config 中移除相关配置并使工作区中的子模块文件夹变为未跟踪状态。

# 语法:git submodule deinit -f <path-to-submodule>
git submodule deinit -f libs/external-lib

        -f (force) 标志是必需的,即使子模块的本地目录有未提交的修改,也会强制注销。

第 2 步:从 Git 索引中删除子模块

        使用 git rm 命令将子模块的目录从 Git 的暂存区(索引)中移除。

# 语法:git rm --cached <path-to-submodule>
git rm --cached libs/external-lib

        --cached 标志表示只从索引中删除,而不删除工作区中的物理文件。如果你也想同时删除物理文件,可以使用 -f (force) 代替 --cachedgit rm -f libs/external-lib

第 3 步:删除物理目录(可选)

        现在子模块已被 Git “遗忘”,你可以安全地删除工作区中的物理文件夹了。

# 如果你在上一步没有使用 -f,手动删除文件夹
rm -rf libs/external-lib
第 4 步:提交更改

        提交这些更改,从而永久地从你的主项目中删除子模块的引用。

git add .gitmodules  # 提交 .gitmodules 的更改
git commit -m "remove submodule external-lib"
第 5 步:清理残留文件(可选但推荐)

        最后,删除子模块在 Git 本地配置中的残留目录(位于 .git/modules/ 下)。这个目录保存着子模块自己的 Git 仓库数据。

rm -rf .git/modules/libs/external-lib

4.2. 完整命令示例(一步到位)

        可以将上述步骤组合起来一次性执行:

# 替换你的子模块路径
SUBMODULE_PATH="libs/external-lib"

# 1. 注销子模块
git submodule deinit -f $SUBMODULE_PATH

# 2. 从索引中删除
git rm --cached $SUBMODULE_PATH

# 3. 删除物理文件夹(如果上一步没用 -f)
rm -rf $SUBMODULE_PATH

# 4. 删除模块的Git数据
rm -rf .git/modules/$SUBMODULE_PATH

# 5. 提交更改
git add .gitmodules
git commit -m "chore: completely remove submodule $SUBMODULE_PATH"

4.3. 命令作用效果

因为子模块在多个地方留下了记录,需要全部清理:

需要清理的地方使用的命令
工作区 (Working Directory)rm -rf (物理文件)
暂存区/索引 (Staging Area)git rm --cached
主项目配置 (.git/config)git submodule deinit
子模块自己的仓库 (.git/modules/)rm -rf .git/modules/path/
子模块列表 (.gitmodules)git add .gitmodules & git commit

4.4. 常见错误和注意事项

不要只删除 .gitmodules 中的一行

       这样做是无效的。Git 的索引和配置中仍然保留着子模块的信息,下次别人克隆你的仓库时会出现问题。

git rm 时不要忘记 --cached

       如果忘记加 --cached,会直接删除你工作区中的物理文件,这可能不是你想要的(你可能想先备份)。

顺序很重要

       先执行 deinit 和 git rm,最后再手动删除物理文件和 .git/modules/ 下的数据。

如果操作出错

       如果你在中间步骤弄错了,最简单的方法是使用 git reset --hard 和 git submodule update --init 回退到初始状态,然后重新开始删除流程。

5. 修改 submodule 的 url

        修改子模块的 URL 是一个常见操作,例如从 HTTPS 协议切换到 SSH 协议,或者仓库地址发生了变化。有几种方法可以实现,推荐使用官方命令。

5.1. 方法一:使用 git submodule set-url 命令(推荐)


这是最直接、最安全的方法,Git 会自动帮你处理所有配置文件的更新。

查看当前子模块信息(可选):

git submodule status

# 或

cat .gitmodules


修改 URL:

bash

# 语法:git submodule set-url <path-to-submodule> <new-url>
git submodule set-url libs/external-lib git@github.com:someuser/external-lib.git


这个命令会自动完成以下操作:

更新 .gitmodules 文件中的 url 字段。

更新主项目本地配置 .git/config 中的 url 字段。

验证更改:

cat .gitmodules

 检查 url 是否已变为新的地址

提交更改:

git add .gitmodules
git commit -m "chore(submodule): update url for external-lib"

同步更改(如果需要):
如果其他协作者已经克隆了项目,他们需要更新本地的子模块关联。他们可以运行:

git submodule sync

这个命令会根据最新的 .gitmodules 文件,更新他们本地 .git/config 中的 URL。

 5.2. 方法二:手动编辑配置文件

还可以手动修改配置文件,效果和 set-url 命令一样,但需要修改两个文件。

编辑 .gitmodules 文件:
打开项目根目录下的 .gitmodules 文件,找到对应的子模块部分,直接修改 url 的值。

[submodule "libs/external-lib"]
    path = libs/external-lib
    url = git@github.com:someuser/external-lib.git # 修改为新的URL

更新本地 Git 配置:
.gitmodules 的更改需要同步到主项目的本地配置 (.git/config) 中。

git submodule sync

提交更改:

git add .gitmodules
git commit -m "chore(submodule): update url for external-lib manually"


5.3. 方法三:先删除再添加(不推荐,仅作了解)

        这是一种“重火力”方法,通常只在上述方法无效或你想彻底重置子模块时使用。这会丢失子模块当前的提交指针,需要重新指定。

<1.> 注销并删除子模块(保留工作目录文件)

git submodule deinit -f libs/external-lib
git rm --cached libs/external-lib
rm -rf .git/modules/libs/external-lib

<2.> 用新的URL重新添加子模块到原路径

git submodule add <new-url> libs/external-lib

<3.> 提交更改

git add .gitmodules
git commit -m "chore(submodule): re-add external-lib with new url"


5.4. 修改 URL 后需要做的操作

        仅仅修改 URL 并提交后,子模块本地已经拉取的内容不会自动更新。URL 只会影响未来的 git submodule update、git pull 等操作。

        如果想确保子模块的工作目录与新的远程仓库同步,通常需要:

进入子模块目录:

cd libs/external-lib

查看当前远程仓库(确认修改是否生效):

git remote -v
# origin 应该显示新的 URL

拉取最新代码(如果需要):

git fetch origin
git checkout main # 或 master,或你需要的分支/提交
git pull origin main

返回主项目并提交(如果子模块有更新):

cd ../..
git add libs/external-lib
git commit -m "chore: update submodule to latest commit"

6. 修改 submodule URL 以及 commit id

        修改子模块的远程仓库地址,并同时将其切换到特定的提交、分支或标签。这需要组合多个 Git 命令来完成。以下是详细步骤和方法。

6.1. 场景分析

开发项目时,可能遇到以下情况:

        子项目仓库地址变了(例如,从 GitHub 迁移到了 GitLab);

        或者希望主项目使用子模块的一个稳定版本(如 tag)而不是最新的 main 分支;

        还可能希望主项目使用一个特定的历史提交,以确保构建的可重复性。

6.2. 方法一:标准流程(分步操作,推荐)

        这是最清晰、最不容易出错的方法。

第 1 步:修改子模块的 URL
使用 git submodule set-url 命令更新 URL。

# 进入主项目根目录
git submodule set-url path/to/your/submodule <new-url>
# 例如:
git submodule set-url tpls/Stim https://gitlab.com/new-group/new-stim-repo.git


第 2 步:进入子模块并切换到目标版本

# 进入子模块目录
cd path/to/your/submodule
# 例如:
cd tpls/Stim

现在,根据你的目标,选择以下操作之一:

切换到特定标签 (Tag):

git fetch origin --tags  # 首先获取所有标签信息
git checkout v1.5.0      # 切换到名为 v1.5.0 的标签
# 或者使用更精确的命令,确保本地标签与远程一致
git checkout tags/v1.5.0


切换到特定分支 (Branch):

git fetch origin         # 获取远程最新信息
git checkout main        # 切换到 main 分支
git pull origin main     # 确保是最新的(如果你想要分支的最新提交)
# 或者,如果你只想锁定在当前远程分支的某个状态,可以只 checkout 不 pull
git checkout main


切换到特定提交 (Commit Hash):

git fetch origin         # 必须执行,确保本地有最新的提交信息
git checkout cae4e9fcde59f9f62650c5cfa7e28c94ad444795  # 切换到完整的提交哈希
# 或者使用缩写(如果唯一)
git checkout cae4e9f


第 3 步:返回主项目并记录新的指针
这是最关键的一步,它将子模块的新状态(新的提交ID)注册到主项目中。

# 返回主项目根目录
cd ../..

# 将子模块目录的当前状态(即新的提交ID)添加到主项目的暂存区
git add path/to/your/submodule
# 例如:
git add tpls/Stim

# 提交更改
git commit -m "chore(submodule): update Stim URL and pin to v1.5.0"
# 提交信息清晰说明了两个操作:更新URL和锁定版本


6.3. 方法二:使用 && 连续执行(一条命令)

    如果已经熟悉流程,可以将上述步骤合并为一条命令。

# 修改URL,进入目录,切换标签,返回并提交
git submodule set-url tpls/Stim <new-url> && \
cd tpls/Stim && \
git fetch origin && \
git checkout v1.5.0 && \
cd ../.. && \
git add tpls/Stim && \
git commit -m "chore: update Stim URL and pin to tag v1.5.0"


6.4. 方法三:直接编辑配置文件并更新(高级)

这种方法让开发者对底层配置有完全的控制力。

手动编辑 .gitmodules 文件:
用文本编辑器打开 .gitmodules,直接修改 url。

[submodule "tpls/Stim"]
    path = tpls/Stim
    url = https://gitlab.com/new-group/new-stim-repo.git  # <- 修改这里
    # branch = main  # 如果有这一行,你也可以修改它来跟踪特定分支


同步配置到本地 Git:

git submodule sync


重新初始化并更新子模块:

# 这会根据新的URL重新获取子模块数据
git submodule update --init --remote --force tpls/Stim
# --init: 如果子模块未初始化则初始化
# --remote: 使用.gitmodules中指定的分支的最新提交(如果不指定分支则用默认分支)
# --force: 强制更新


进入子模块并切换到目标版本(同方法一的第2步):

cd tpls/Stim
git fetch origin --tags
git checkout v1.5.0
cd ../..


记录新的指针(同方法一的第3步):

git add tpls/Stim
git commit -m "chore: update Stim URL and pin to v1.5.0"


6.5. 重要注意事项

 
branch 配置项:
        在 .gitmodules 中,可以有一个可选的 branch = main 项。它不意味着子模块被锁定在 main 分支,而是意味着当你在主项目中执行 git submodule update --remote 时,Git 会去获取该远程分支的最新提交并更新子模块。如果你想要一个固定的标签或提交,不应该依赖这个配置,而是用 git checkout 和 git add 来锁定。

.gitmodules vs .git/config:

        .gitmodules 是提交到仓库的模板文件,供所有协作者使用。

        git submodule sync 会将 .gitmodules 的更新同步到本地的 .git/config 文件中。

        主项目真正记录的子模块版本是那个 160000 模式的提交哈希,它存储在 Git 的树对象中,通过 git add 来更新。

告知你的团队:
        在修改了子模块的 URL 并推送到远程后,其他协作者需要运行以下命令来更新他们的本地配置:

git pull
git submodule sync
git submodule update --init --recursive

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值