介绍
Git 子模块(submodule)是一个强大的功能,它允许你将外部仓库包含在自己的项目中。当你的项目依赖于单独维护的外部库或组件时,此功能特别有用。通过使用子模块,你可以保持这些依赖项的最新状态并进行良好的管理。
在本教程中,你将学习如何检查仓库中 Git 子模块的状态,了解对它们所做的更改,并确保它们与它们的源仓库正确同步。
Git 子模块(submodule)是一个强大的功能,它允许你将外部仓库包含在自己的项目中。当你的项目依赖于单独维护的外部库或组件时,此功能特别有用。通过使用子模块,你可以保持这些依赖项的最新状态并进行良好的管理。
在本教程中,你将学习如何检查仓库中 Git 子模块的状态,了解对它们所做的更改,并确保它们与它们的源仓库正确同步。
让我们从创建一个带有子模块的示例仓库开始,以便为我们的学习提供一个实际的环境。
首先,我们将创建一个新的主仓库,并在其中添加我们的子模块。打开你的终端并运行以下命令:
cd ~/project
mkdir main-repo
cd main-repo
git init
你应该看到类似如下的输出:
Initialized empty Git repository in /home/labex/project/main-repo/.git/
现在,让我们在主仓库中创建一个简单的文件:
echo "## Main Repository" > README.md
git add README.md
git commit -m "Initial commit"
输出应该表明你已经创建了你的第一个提交:
[master (root-commit) xxxxxxx] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
现在让我们向主仓库添加一个子模块。在本教程中,我们将使用一个小的公共仓库作为我们的子模块:
git submodule add https://github.com/libgit2/libgit2-backends.git libs/libgit2-backends
此命令将克隆仓库并将其作为子模块添加到 libs/libgit2-backends 目录中。你应该看到类似如下的输出:
Cloning into '/home/labex/project/main-repo/libs/libgit2-backends'...
remote: Enumerating objects: xxx, done.
remote: Counting objects: 100% (xxx/xxx), done.
remote: Compressing objects: 100% (xxx/xxx), done.
remote: Total xxx (delta xx), reused xxx (delta xx), pack-reused xxx
Receiving objects: 100% (xxx/xxx), xxx KiB | xxx KiB/s, done.
Resolving deltas: 100% (xxx/xxx), done.
当你添加一个子模块时,Git 会在你的仓库中创建一个 .gitmodules 文件,该文件跟踪子模块的 URL 和路径。让我们看看这个文件:
cat .gitmodules
你应该看到类似如下的内容:
[submodule "libs/libgit2-backends"]
path = libs/libgit2-backends
url = https://github.com/libgit2/libgit2-backends.git
我们也要检查一下我们仓库的状态:
git status
你应该看到输出表明新的 .gitmodules 文件和子模块目录都已添加:
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .gitmodules
new file: libs/libgit2-backends
让我们提交这些更改以完成我们的设置:
git commit -m "Add libgit2-backends submodule"
你现在应该有一个成功设置了子模块的仓库。
现在我们有了一个带有子模块的仓库,让我们学习如何检查子模块的状态并理解输出的含义。
Git 提供了一个特定的命令来检查子模块的状态。运行以下命令:
cd ~/project/main-repo
git submodule status
你应该看到类似如下的输出:
+abcdef1234567890abcdef1234567890abcdef12 libs/libgit2-backends (v1.0.0-123-gabcdef12)
让我们理解一下这个输出的含义:
第一个字符可以是以下之一:
+:表示子模块提交与主仓库中注册的提交不同 (空格):表示子模块与注册的内容同步-:表示子模块未初始化U:表示子模块中存在合并冲突字母数字字符串是子模块中当前检出提交的哈希值。
路径显示了子模块在你的仓库中的位置。
括号中的文本显示了关于检出提交的附加信息,例如标签或分支名称。
要获取关于你的子模块的更详细信息,你可以使用以下命令:
git submodule
这将显示与状态命令类似的信息,但格式不同。
你也可以使用标准的 git status 命令来查看子模块中的更改:
git status
如果子模块没有更改,你将在输出中看不到任何关于它的提及。但是,如果子模块的检出提交或子模块内的文件有更改,git status 将显示此信息。
让我们检查一下我们子模块的内容:
cd ~/project/main-repo
ls -la libs/libgit2-backends/
你将看到来自 libgit2-backends 仓库的文件。请注意,子模块本质上是你的主仓库中的一个完整的 Git 仓库。你可以通过检查是否存在 .git 目录来验证这一点:
ls -la libs/libgit2-backends/.git
你可能不会直接看到 .git 目录,而是一个指向实际 Git 仓库数据的文件的,这些数据存储在你的主仓库的 .git/modules 目录中。这就是 Git 管理子模块的方式。
主仓库存储了对子模块仓库中特定提交的引用。此引用是 Git 用来知道在克隆你的仓库或更新子模块时应该检出哪个版本的子模块。
让我们看看我们的主仓库引用的提交:
cd ~/project/main-repo
git ls-files --stage libs/libgit2-backends
输出将显示一个提交哈希值,这是主仓库正在跟踪的子模块的特定提交。
在使用子模块时,一个常见的任务是保持它们与它们的远程仓库同步。让我们学习如何更新我们的子模块。
如果你刚刚克隆了一个包含子模块的仓库,你需要初始化并更新它们。对于我们现有的仓库,我们可以用以下命令演示这个过程:
cd ~/project/main-repo
git submodule init
git submodule update
init 命令初始化你的子模块配置,而 update 命令获取数据并检出你的主仓库中指定的提交。
你也可以组合这些命令:
git submodule update --init
如果你想将子模块更新到其远程仓库中的最新提交,你可以使用:
cd ~/project/main-repo
git submodule update --remote libs/libgit2-backends
此命令从远程仓库获取最新的更改并更新子模块。你应该看到输出表明 Git 正在获取更改。
运行此命令后,让我们检查子模块的状态:
git submodule status
你将注意到输出现在在开头显示一个加号(+),表明子模块的检出提交与主仓库中记录的不同:
+abcdef1234567890abcdef1234567890abcdef12 libs/libgit2-backends (origin/HEAD)
要确认对你的主仓库的更改,请运行:
git status
你应该看到输出表明子模块已被修改:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: libs/libgit2-backends (new commits)
要在你的主仓库中记录更新的子模块状态,你需要添加并提交更改:
git add libs/libgit2-backends
git commit -m "Update libgit2-backends submodule to latest version"
输出应该表明你已经成功提交了新的子模块引用。
在提交更新的子模块引用后,让我们再次检查状态:
git submodule status
输出不应再在开头有加号,表明子模块现在与主仓库中记录的内容同步:
abcdef1234567890abcdef1234567890abcdef12 libs/libgit2-backends (origin/HEAD)
git submodule update 命令有几个选项,用于控制如何执行更新:
--remote:更新到远程跟踪分支上的最新提交--merge:如果当前分支落后于远程分支,则合并更改--rebase:如果当前分支落后于远程分支,则变基更改--recursive:也更新嵌套的子模块对于大多数基本用例,git submodule update --remote 就足够了。
有时你需要处理子模块内的更改。在这一步中,我们将学习如何在子模块内进行和管理更改。
要处理子模块,你需要导航到它的目录:
cd ~/project/main-repo/libs/libgit2-backends
从这里,你可以使用标准的 Git 命令来查看关于子模块仓库的信息:
git status
git log -3 --oneline
git status 命令显示子模块仓库的当前状态,而 git log 显示最近的提交。
让我们对子模块中的一个文件进行简单的更改。首先,让我们创建一个新文件:
echo "## My notes on libgit2-backends" > NOTES.md
现在让我们检查一下我们更改的状态:
git status
你应该看到输出表明你有一个未跟踪的文件:
Untracked files:
(use "git add <file>..." to include in what will be committed)
NOTES.md
让我们将此更改添加到子模块并提交:
git add NOTES.md
git commit -m "Add notes file"
你应该看到输出确认你在子模块内的提交。
现在,让我们回到主仓库并检查状态:
cd ~/project/main-repo
git status
你应该看到输出表明子模块已被修改:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: libs/libgit2-backends (new commits)
要在你的主仓库中记录子模块的新状态,你需要添加并提交更改:
git add libs/libgit2-backends
git commit -m "Update libgit2-backends with notes file"
输出应该表明你已经成功提交了新的子模块引用。
要查看关于子模块更改的更详细信息,你可以使用:
git diff --submodule
此命令显示在每个已更改的子模块中添加或删除的提交范围。
在处理子模块中的更改时,请记住此工作流程:
这个两步提交过程(首先在子模块中,然后在主仓库中)对于正确跟踪对子模块的更改至关重要。
在本教程中,你已经学习了如何使用 Git 子模块,重点是检查它们的状态和进行更新。以下是你完成的内容:
Git 子模块提供了一种强大的方式,可以在你的项目中包含外部仓库,从而允许你有效地管理依赖项。通过了解如何检查它们的状态和管理更新,你可以确保你的项目与它的依赖项保持正确同步。
需要记住的关键命令:
git submodule status - 检查子模块的当前状态git submodule update --remote - 将子模块更新到它们的最新版本git add <submodule-path> - 暂存对子模块引用的更改git diff --submodule - 查看子模块中的详细更改有了这些技能,你可以有效地管理通过子模块合并外部代码的 Git 仓库。