Git:多个项目可以使用相同的子模块工作副本吗?
我是Git的新手。 比方说,我有两个git存储库,其中添加了相同的库作为子模块:Git:多个项目可以使用相同的子模块工作副本吗?,git,git-submodules,Git,Git Submodules,我是Git的新手。 比方说,我有两个git存储库,其中添加了相同的库作为子模块: /home/projects/project1/library_XYZ /home/projects/project2/library_XYZ 也就是说,我正在同时处理项目和库。当我对库进行更改时,比如在/home/projects/project1/library_XYZ中,我必须将这些更改推送到/home/projects/project2/library_XYZ中,使它们可用于project2,对吗?我认为
/home/projects/project1/library_XYZ
/home/projects/project2/library_XYZ
也就是说,我正在同时处理项目和库。当我对库进行更改时,比如在/home/projects/project1/library_XYZ
中,我必须将这些更改推送到/home/projects/project2/library_XYZ
中,使它们可用于project2
,对吗?我认为这是不愉快的,原因有二:
- 我将不得不构建两次
library\u XYZ
- 我有一个不必要的冗余,与实际的项目组织相矛盾
library_XYZ
克隆到相同的本地目录,即使文件按如下方式组织
/home/projects/project1
/home/projects/project2
/home/projects/library_XYZ
而library_XYZ
仍然是这两个项目的子模块
我认为这可能与有关,这是没有答案的,尽管我的设置有些不同。将共享依赖项设置为子模块很容易。git submodule命令不会自动执行此操作,但子模块只不过是一个嵌套的存储库——git不要求任何实际的存储库或其工作树位于任何特定位置 设置libraryXYZ repo以用作共享子模块
# a submodule is just a repository. We're going to share this one.
git clone u://r/libraryXYZ
# and keep its worktree right here:
( cd libraryXYZ; git config core.worktree .. )
然后,从任意位置使用子模块克隆项目,并将其设置为使用共享模块:
git clone u://r/project1
cd project1
git submodule init
echo gitdir: path/to/shared/libraryXYZ/.git > libraryXYZ/.git
现在project1
的libraryXYZ
子模块将使用共享的libraryXYZ
repo和工作树
将构建系统设置为使用相同的工作树,就完成了。当然,您可以让git告诉您在任何给定的回购协议中这些内容的位置:
# for example to see where all a project's submodules' parts are kept
git submodule foreach git rev-parse --git-dir --show-toplevel
# or for just one:
git --git-dir=$project1/libraryXYZ/.git rev-parse --git-dir --show-toplevel
(后期编辑:值得记住,这可能会使从一个项目执行
git子模块更新有点太容易,而没有意识到您还更改了共享依赖项的每个其他项目的构建环境。)自git 2.5以来,您可以执行以下操作:
删除/home/projects/project2/library\u XYZ
删除/home/projects/project2/.git/modules/library\u XYZ
cd/home/projects/project1/library\u XYZ
在/home/projects/project1/library\u XYZ中创建分支项目2
运行git工作树添加.././project2/library\u XYZ project2
现在,/home/projects/project1/.git/modules/library_XYZ在两个项目之间共享。我和你一样有一些问题:作为子模块的大型通用实用程序库,以及许多依赖它的项目。我不想为实用程序库的每个实例创建单独的签出
jthill提出的解决方案很好,但它只解决了问题的前一半,即如何让git满意
缺少的是如何让构建系统满意,它需要实际的文件,而不关心gitlink引用
但是如果你把他的想法和一个符号链接结合起来,你就会得到你想要的
为了实现这一点,让我们从您的示例中的项目开始
/home/projects/project1
/home/projects/project2
/home/projects/library_XYZ
假设project1和project2都已将library_XYZ作为子模块添加,并且当前所有三个项目都包含library_XYZ的完整签出
要用指向库签出的共享符号链接替换库子模块的完全签出,请执行以下操作:
sharedproject="/home/projects/library_XYZ"
superproject="/home/projects/project1"
submodule="library_XYZ"
cd "$superproject"
(cd -- "$submodule" && git status) # Verify that no uncommited changes exist!
(cd -- "$submodule" && git push -- "$sharedproject") # Save any local-only commits
git submodule deinit -- "$submodule" # Get rid of submodule's check-out
rm -rf .git/modules/"$submodule" # as well as of its local repository
mkdir -p .submods
git mv -- "$submodule" .submods/
echo "gitdir: $sharedproject.git" > ".submods/$submodule/.git"
ln -s -- "$sharedproject" "$submodule"
echo "/$submodule" >> .gitignore
然后对/home/projects/project2重复与$superproject相同的步骤
下面是对所做工作的解释:
首先,使用“git submodule deinit”删除子模块签出,留下库作为空目录。确保在执行此操作之前提交任何更改,因为这将删除签出
接下来,我们使用“git push”to/home/projects/library_XYZ将所有尚未推送到共享项目的本地提交保存到签出
如果由于未为此设置远程规范或参照规范而无法执行此操作,则可以执行以下操作:
(saved_from=$(basename -- "$superproject"); \
cd -- "$submodule" \
&& git push -- "$sharedproject" \
"refs/heads/*:refs/remotes/$saved_from/*")
这将子模块本地存储库的所有分支的备份保存为/home/projects/library_XYZ中的远程分支。$superproject目录的basename将用作远程项目的名称,即。E本例中的project1或project2
当然,在/home/projects/library_XYZ中不存在真正的远程名称,但是保存的分支将显示为在那里执行“git branch-r”时显示的分支
作为保护措施,上述命令中的refspec不会以“+”开头,因此“git push”不会意外地覆盖/home/projects/library_XYZ中已经存在的任何分支
接下来,将删除.git/modules/library_XYZ以节省空间。我们可以这样做,因为我们不再需要使用“git submodule init”或“git submodule update”。这种情况是因为我们将与子模块共享/home/projects/library_XYZ的签出目录和.git目录,从而避免两者的本地副本
然后让git将空的子模块目录重命名为“.submods/library_XYZ”,这是一个项目中的文件永远不会直接使用的(隐藏)目录
接下来,我们将jthill的部分解决方案应用于该问题,并在.submods/library_XYZ中创建一个gitlink文件,使git将/home/projects/library_XYZ作为子模块的工作树和git repo
现在有了新的东西:我们创建了一个相对名称为“library_XYZ”的符号链接,它指向/home/projects/library_XYZ。此符号链接将不受版本控制,因此我们将其添加到.gitignore文件中
project1和project2中的所有生成文件都将使用库_XYZ符号链接,就像它是一个普通的子目录一样,但实际上可以从/home/projects/library _XYZ中的工作树中找到文件
除了git,没有人真正使用.submods/library_XYZ
然而
$ test ! -e library_XYZ && ln -s .submods/library_XYZ
library_XYZ/libsharedutils.a:
cd library_XYZ && $(MAKE) libsharedutils.a
library_XYZ/libsharedutils.a:
test ! -e library_XYZ && ln -s .submods/library_XYZ
cd library_XYZ && $(MAKE) libsharedutils.a
(n=create_missing_dirs.sh && cat > "$n" << 'EOF' && chmod +x -- "$n")
#! /bin/sh
for dir in .submods/*
do
sym=${dir#*/}
if test -d "$dir" && test ! -e "$sym"
then
echo "Creating $sym"
ln -snf -- "$dir" "$sym"
fi
done
EOF
sharedproject="/home/projects/library_XYZ"
submodule="library_XYZ"
ln -sn -- "$sharedproject" "$submodule"
echo "gitdir: $sharedproject.git" > ".submods/$submodule/.git"
sudo mount -o bind /home/projects/library_XYZ /home/projects/project1/library_XYZ
cd /home/projects/project1/
git submodule deinit library_XYZ
rm -rf .git/modules/library_XYZ