Git 中工作树、子模块和子树的使用指南
在本地环境中管理多个工作区和仓库实例时,Git 提供了多种实用功能,如工作树(Worktrees)、子模块(Submodules)和子树(Subtrees)。下面将详细介绍这些功能的使用方法。
1. 添加子树
在 Git 中添加子项目作为子树,最基本的操作是指定前缀、仓库的远程路径,还可以选择指定分支。以下是具体步骤:
1.
克隆远程项目
:
$ git clone ../remotes/myproj.git myproject
此命令将远程项目
myproj
克隆到本地的
myproject
目录。克隆完成后,进入该目录并查看文件:
$ cd myproject
$ ls
file1.txt file2.txt file3.txt
-
添加子树
:假设还有一个名为
subproj的项目,现在将其master分支作为子树添加到myproject中:
~/subtrees/local$ cd myproject
~/subtrees/local/myproject$ git subtree add --prefix subproject ~/subtrees/remotes/subproj.git master
执行该命令后,Git 会从远程仓库获取数据并添加子树。查看目录结构和日志:
~/subtrees/local/myproject$ ls
file1.txt file2.txt file3.txt subproject/
~/subtrees/local/myproject$ ls subproject
subfile1.txt subfile2.txt
~/subtrees/local/myproject$ git log --oneline
7d4f436 Add 'subproject/' from commit '906b5234f366bb2a419953a1edfb590aadc32263'
906b523 Add subfile2
5f7a7db Add subfile1
fada8bb Add file3
ef21780 Add file2
73e59ba Add file1
-
使用 squash 选项添加子树
:默认情况下,添加子树会包含项目的完整历史。若想避免添加所有历史,可以使用
squash选项。首先重置项目:
$ git reset --hard HEAD~1
然后添加新的远程引用:
~/subtrees/local/myproject$ git remote add sub_origin ~/subtrees/remotes/subproj.git
使用
squash
选项添加子树:
~/subtrees/local/myproject$ git subtree add --prefix subproject --squash sub_origin master
查看日志:
$ git log --oneline
6b109f0 Merge commit 'f7c3147d6df0609745228cc5083bb6c7d0b07d1a' as 'subproject'
f7c3147 Squashed 'subproject/' content from commit 906b523
fada8bb Add file3
ef21780 Add file2
73e59ba Add file1
2. 更新子树
如果需要将远程的更改拉取到子树中,可以使用
git subtree pull
命令:
$ git subtree pull --prefix subproject sub_origin master --squash
该命令会将远程的最新内容拉取到子树区域,并再次压缩历史。若不想压缩历史,可以省略
--squash
选项。
此外,还有
git subtree merge
命令,可用于将提交合并到由
--prefix
参数指定的子项目中。
git subtree merge
用于合并本地对子项目的更改,而
git subtree pull
则用于从远程获取更改。
需要注意的是,Git 中还有一种名为
subtree
的合并策略,它与
git subtree
命令不同。
git subtree
是一个集成到 Git 中的脚本,而
subtree
合并策略用于合并两个树,其中一个是另一个的子树。
3. 使用子树拆分功能
git subtree split
子命令可用于将子项目的内容提取到一个单独的分支中。它会提取与
<prefix>
相关的内容和历史,并将结果内容放在新分支的根目录,而不是子目录中。
例如,现有如下项目结构:
~/subtrees/local/myproject$ ls
file1.txt file2.txt file3.txt subproject/
若要提取
subproject
子目录的内容和历史,可以使用以下命令:
~/subtrees/local/myproject$ git subtree split --prefix=subproject --branch=split_branch
查看新分支的内容和日志:
~/subtrees/local/myproject$ git checkout split_branch
Switched to branch 'split_branch'
~/subtrees/local/myproject$ ls
subfile1.txt subfile2.txt
~/subtrees/local/myproject$ git log --oneline
906b523 Add subfile2
5f7a7db Add subfile1
4. 从拆分内容创建新项目
可以将拆分出的内容转移到另一个项目中。以下是具体步骤:
1.
创建新的 Git 项目
:
~/subtrees/local/myproject$ cd ~/
~$ mkdir newproj
~$ cd newproj
~/newproj$ git init
- 将拆分出的分支内容拉取到新项目中 :
~/newproj$ git pull ~/subtrees/local/myproject split_branch
查看新项目的内容和日志:
~/newproj$ ls
subfile1.txt subfile2.txt
~/newproj$ git log --oneline
906b523 Add subfile2
5f7a7db Add subfile1
5. 子树推送
git subtree push
命令支持将子项目目录拆分并推送到远程仓库。例如,将
subproject
目录拆分并推送到
sub_origin
远程引用的
new_branch
分支:
~/subtrees/local/myproject$ git subtree push --prefix=subproject sub_origin new_branch
6. 工作树的使用
工作树允许在不同区域同时处理多个分支,且都连接到同一个本地仓库。以下是使用工作树的步骤:
1.
准备工作
:需要有互联网访问权限,并完成相关的 GitHub 账户设置和仓库克隆。将
calc2
仓库拆分为三个项目:
super_calc
、
sub_ui
和
sub_docs
,并在 GitHub 上进行 Fork。
2.
克隆项目
:在新目录中克隆
super_calc
项目:
$ git clone https://github.com/<your github userid>/super_calc.git
-
创建工作树
:同时处理
master分支和features分支,为features分支创建新的工作树:
$ git worktree add -b features ../super_calc_features origin/features
-
编辑文件并提交
:进入新的工作树目录,编辑
calc.html文件并提交更改:
$ cd ../super_calc_features
Edit calc.html and change
<title>Calc</title>
to
<title> github_user_id's Calc</title>
$ git commit –am "Updating title"
- 查看分支和日志 :切换回原工作树,查看分支和日志:
$ cd ../super_calc
$ git branch
$ git log --oneline features
-
移除工作树
:不再需要工作树时,先移除实际目录,再使用
prune选项清除工作树引用:
$ rm –rf ../super_calc_features
$ git worktree prune
7. 子模块的使用
子模块是从原始项目(超级项目)链接到其他项目的一种方式。以下是使用子模块的步骤:
1.
准备工作
:需要有互联网访问权限,并完成相关的 GitHub 账户设置和仓库克隆。
2.
添加子模块
:在
super_calc
项目中添加
sub_ui
作为子模块:
$ git submodule add https://github.com/<your github userid>/sub_ui sub_ui
- 提交和推送 :提交并推送子模块映射和数据到本地和远程仓库:
$ git commit -m "Add submodule sub_ui"
$ git push
- 克隆包含子模块的项目 :克隆一个新的包含子模块的项目副本:
$ cd ..
$ git clone https://github.com/<your github userid>/super_calc super_calc2
- 初始化子模块 :进入新克隆的项目目录,查看子模块状态并初始化:
$ cd super_calc2
$ ls sub_ui
$ git submodule status
$ git submodule update --init
-
更新子模块代码
:进入子模块目录,编辑
calc.html文件并提交更改:
$ cd sub_ui
Edit calc.html and change
<title>Advanced Calculator</title>
to
<title> your_name_here Advanced Calculator</title>
$ git commit -am "Update title"
- 更新超级项目 :返回超级项目目录,查看子模块状态并提交更新:
$ cd ..
$ git submodule status
$ git status
$ git commit -am "Update for submodule sub_ui"
$ git push
综上所述,工作树、子模块和子树都是 Git 中非常实用的功能,但在大多数情况下,更好的做法是在构建或部署过程中,将其他仓库构建的可交付成果作为工件使用。应仅在仓库之间存在真正的源依赖关系,且需要这种紧密的源连接时,才使用子模块和子树。过多的此类依赖可能表明需要对仓库之间的代码进行重构。
Git 中工作树、子模块和子树的使用指南
8. 各功能操作流程总结
为了更清晰地展示工作树、子模块和子树的操作流程,下面通过表格和流程图进行总结。
8.1 操作步骤表格
| 功能 | 操作步骤 | 命令示例 |
|---|---|---|
| 添加子树 |
1. 克隆远程项目
2. 添加子树 3. 可选:使用 squash 选项添加子树 |
1.
git clone ../remotes/myproj.git myproject
2.
git subtree add --prefix subproject ~/subtrees/remotes/subproj.git master
3.
git subtree add --prefix subproject --squash sub_origin master
|
| 更新子树 | 拉取远程更改到子树 |
git subtree pull --prefix subproject sub_origin master --squash
|
| 子树拆分 | 提取子项目内容到单独分支 |
git subtree split --prefix=subproject --branch=split_branch
|
| 从拆分内容创建新项目 |
1. 创建新 Git 项目
2. 拉取拆分分支内容到新项目 |
1.
git init
2.
git pull ~/subtrees/local/myproject split_branch
|
| 子树推送 | 拆分并推送子项目目录到远程 |
git subtree push --prefix=subproject sub_origin new_branch
|
| 工作树使用 |
1. 准备工作
2. 克隆项目 3. 创建工作树 4. 编辑文件并提交 5. 查看分支和日志 6. 移除工作树 |
1. Fork 项目到 GitHub
2.
git clone https://github.com/<your github userid>/super_calc.git
3.
git worktree add -b features ../super_calc_features origin/features
4. 编辑文件并
git commit –am "Updating title"
5.
git branch
和
git log --oneline features
6.
rm –rf ../super_calc_features
和
git worktree prune
|
| 子模块使用 |
1. 准备工作
2. 添加子模块 3. 提交和推送 4. 克隆包含子模块的项目 5. 初始化子模块 6. 更新子模块代码 7. 更新超级项目 |
1. Fork 项目到 GitHub
2.
git submodule add https://github.com/<your github userid>/sub_ui sub_ui
3.
git commit -m "Add submodule sub_ui"
和
git push
4.
git clone https://github.com/<your github userid>/super_calc super_calc2
5.
git submodule update --init
6. 编辑文件并
git commit -am "Update title"
7.
git commit -am "Update for submodule sub_ui"
和
git push
|
8.2 操作流程 mermaid 流程图
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B{选择功能}:::decision
B -->|添加子树| C(克隆远程项目):::process
C --> D(添加子树):::process
D --> E{是否使用 squash 选项}:::decision
E -->|是| F(使用 squash 选项添加子树):::process
E -->|否| G(完成添加子树):::process
B -->|更新子树| H(拉取远程更改到子树):::process
B -->|子树拆分| I(提取子项目内容到单独分支):::process
B -->|从拆分内容创建新项目| J(创建新 Git 项目):::process
J --> K(拉取拆分分支内容到新项目):::process
B -->|子树推送| L(拆分并推送子项目目录到远程):::process
B -->|工作树使用| M(准备工作):::process
M --> N(克隆项目):::process
N --> O(创建工作树):::process
O --> P(编辑文件并提交):::process
P --> Q(查看分支和日志):::process
Q --> R(移除工作树):::process
B -->|子模块使用| S(准备工作):::process
S --> T(添加子模块):::process
T --> U(提交和推送):::process
U --> V(克隆包含子模块的项目):::process
V --> W(初始化子模块):::process
W --> X(更新子模块代码):::process
X --> Y(更新超级项目):::process
G --> Z([结束]):::startend
H --> Z
I --> Z
K --> Z
L --> Z
R --> Z
Y --> Z
9. 各功能适用场景分析
不同的功能在不同的场景下有其独特的优势,下面对工作树、子模块和子树的适用场景进行分析。
9.1 工作树适用场景
-
并行开发
:当需要同时在多个分支上进行开发时,工作树可以让你在不同的工作区独立处理各个分支,避免频繁切换分支带来的不便。例如,开发人员可以在一个工作树中处理
master分支的稳定版本,同时在另一个工作树中进行feature分支的新功能开发。 - 快速验证 :在不影响主工作区的情况下,可以快速验证某个分支的更改。比如,需要验证一个实验性的功能分支,就可以创建一个新的工作树来进行测试。
9.2 子模块适用场景
- 项目复用 :当多个项目需要共享同一个代码库时,使用子模块可以将共享代码作为一个独立的仓库进行管理,方便在不同项目中复用。例如,多个项目都依赖同一个工具库,就可以将该工具库作为子模块添加到各个项目中。
- 独立开发 :子模块允许各个子项目独立开发和维护,每个子项目都有自己的版本控制。这样,不同的开发团队可以专注于自己负责的子项目,而不会影响其他部分。
9.3 子树适用场景
- 集成外部项目 :当需要将一个外部项目集成到自己的项目中,并且希望将其历史记录也包含进来时,子树是一个不错的选择。例如,将一个开源的库集成到自己的项目中,使用子树可以保留该库的完整历史。
- 代码合并 :在进行代码合并时,子树可以更好地处理目录结构的差异。当两个项目的目录结构不同,但需要将其中一个项目作为子项目合并到另一个项目中时,子树可以自动调整目录结构,使合并过程更加顺利。
10. 注意事项和最佳实践
在使用工作树、子模块和子树时,需要注意一些事项,并遵循一些最佳实践。
10.1 注意事项
-
子模块初始化
:克隆包含子模块的项目时,需要手动初始化子模块,否则子模块可能不会正常工作。可以使用
--recursive选项在克隆时自动初始化子模块。 -
子树历史管理
:使用子树时,要注意历史记录的管理。如果不需要保留完整的历史记录,可以使用
squash选项来简化历史。 - 工作树清理 :不再使用工作树时,要及时清理,避免占用过多的磁盘空间。
10.2 最佳实践
- 明确依赖关系 :在使用子模块和子树时,要明确各个项目之间的依赖关系,避免出现循环依赖等问题。
- 定期更新 :定期更新子模块和子树,确保使用的是最新的代码。
- 文档记录 :对于复杂的项目结构,要做好文档记录,方便其他开发人员理解和维护。
通过合理使用工作树、子模块和子树,可以提高开发效率,更好地管理项目结构和依赖关系。但在实际应用中,要根据具体的项目需求和场景选择合适的功能,并注意相关的注意事项和最佳实践。
超级会员免费看
1267

被折叠的 条评论
为什么被折叠?



