我知道编辑这个网站吗?

Git 子模块教程

本节内容已经过时,可能具有误导性或无效。请谨慎对待这里的任何说明。如有疑问,请向社区求助

斐济的子模块

Fiji 托管在一个主 git 存储库上,其中包含几个声明的子模块,例如 TrakEM2。

使用 git,在存储库的任何子目录中执行的任何 git 命令都会影响整个 git 存储库。

子模块虽然 fiji 存储库中的文件夹存在,但作为有所不同:只有文件夹名称作为路径指针,以及该子模块的当前修订版(“提交名称”,即 40 位十六进制字符串,它是每个提交的唯一标识符)一起注册为属于 fiji 的 git 存储库。

###检查子模块

每个子模块都是一个完整的 git 存储库因此,在子模块的文件夹中执行的任何 git 命令都会影响 git 存储库,而不是 fiji 的。

但是,要使用子模块,您必须克隆该存储库。有关详细信息,请参阅 Downloading and Building Fiji From Source 页面的 Submodules 部分。

子模块工作流程

在子模块内部工作时通常的命令序列:

~/fiji$ cd TrakEM2
~/fiji/plugins/trakem2$ git status

假设您观察到一些未上演的变化。只需添加并提交它们:

~/fiji/plugins/trakem2$ git add path/to/some_file.java
~/fiji/plugins/trakem2$ git commit

您可以在子模块内随心所欲地工作,如果您想将某些内容提交给斐济(超级项目),请首先确保您对子模块进行了更改!

然后向上移动并添加 fiji 内子模块的当前版本。

~/fiji/plugins/trakem2$ git push
~/fiji/plugins/trakem2$ cd ..
~/fiji$ git add TrakEM2
~/fiji$ git commit

当心: adding “TrakEM” and “TrakEM/” is not the same at all! The latter would add all non-ignorable files under TrakEM2’s subfolder into fiji’s repository, which is NOT what you want. If you screwed up, use git reset --hard before proceeding to unstage any changes in fiji’s git repository. 完成上述操作后,fiji 已更新以跟踪最新的 TrakEM2 提交。 如果对安排感到满意,那么更改子模块到共享存储库以供其他人查看。请记住分别子模块和斐济的存储库本身彼此!如果你只自定义斐济,那么无论谁拉取斐济,都不会看到子模块分支的新HEAD,这会导致错误。

~/fiji$ cd TrakEM2/
~/fiji/plugins/trakem2$ git push
~/fiji/plugins/trakem2$ cd ..
~/fiji$ git push

解决子模块冲突

当合并并重新定位斐济时,您可能最终不得不解决模块版本中的冲突。接下来的两节旨在帮助您解决这些冲突。

合并时子模块冲突

当您运行 git mergegit pull(实际运行 git fetch,然后运行 git merge)时,您最有可能在合并时发生子模块冲突。如何解决这些冲突可以在 Git Conflicts wiki 页面上阅读。

变基本时子模块冲突

变基时子模块版本中的冲突不同。例如,假设我遇到以下情况:

o---o----o----o----o main  
 \  
  A----B----C-----D----E----F server

我想通过执行以下操作将服务器重新设置主服务器:

git checkout server  
git rebase -i main

-i选项意味着我首先会看到要移植到main上的提交列表,在上面称为A、B、C、D、E和F。之后可能会进行一些更改(可能有一些实际上您并不想包含在变基版本中的提交),变基开始。我的第一个错误如下:

Automatic cherry-pick failed.  After resolving the conflicts,  
mark the corrected paths with 'git add <paths>', and  
run 'git rebase --continue'  
Could not apply 1f7b713... Various changes to make the server work better

如果您一条消息说您必须解决冲突收到,这意味着“git status”会告诉您它们是什么。在这种情况下我得到:

VIB: needs merge  
# Not currently on any branch.  
# Changes to be committed:  
#   (use "git reset HEAD <file>..." to unstage)  
#  
#  modified:   run-server.sh  
#  deleted:    server-init.d-script  
#  modified:   staged-plugins/VIB_.config  
#  
# Changed but not updated:  
#   (use "git add/rm <file>..." to update what will be committed)  
#   (use "git checkout -- <file>..." to discard changes in working directory)  
#  
#  modified:   ImageJA  
#  modified:   TrakEM2  
#  unmerged:   VIB  
#  modified:   java/linux  
#  modified:   java/linux-amd64  
#  deleted:    mpicbg  
#  
# Untracked files:  
#   (use "git add <file>..." to include in what will be committed)  
#  
[... various irrelevant untracked files ...]

这种情况下,只有一个问题:VIB子模块的版本冲突。

假设现在的情况对应于下图:

                     A'---B' HEAD  
                    /  
o---o----o----o----o main  
 \  
  A----B----C-----D----E----F server ORIG_HEAD

首先,重要的是要提交尝试对版本进行哪些更改,从上面的“无法应用”行中获取部分 SHA1 总并提交其提交给 git show,因此,git show 1f7b713。这显示了该提交导入的文件,但了解我们只查找与 VIB 子模块相关的行,它们是:

diff --git a/VIB b/VIB  
index c03c2cc..b6d78c8 160000  
--- a/VIB  
+++ b/VIB  
@@ -1 +1 @@  
-Subproject commit c03c2cc7d150087d91879012e1b312e3b2957733  
+Subproject commit b6d78c8c390072d89059956d4d3596114c6301f1

现在,为了检查我们是否了解发生了什么,请运行三个版本的 diff 命令。首先,显示此变基中最后一次成功提交与工作树版本之间的差异:

 git diff --base VIB  
* Unmerged path VIB  
diff --git a/VIB b/VIB  
index c03c2cc..764f65b 160000  
--- a/VIB  
+++ b/VIB  
@@ -1 +1 @@  
-Subproject commit c03c2cc7d150087d91879012e1b312e3b2957733  
+Subproject commit 764f65baee6af310cac4879a52805d7bffcd4dd0

这向我们表明旧提交中的版本符合我们的预期(很好!)+行中的版本是我们工作树中的版本,或者如果你执行“( cd VIB && git show HEAD )”,你会看到什么。因此,在这种情况下,我将 VIB 切换为我们选择的提交尝试引入的版本是一个不错的主意,即b6d78c8c390

( cd VIB && git checkout b6d78c8c390 )  
git add VIB

现在我们应该可以继续了,git rebase --continue

####关于“我们的”和“他们的”的注释

如果您在变基时使用git diff --theirsgit diff --ours,那么你可能会感到困惑。本质上:

  • git diff --theirs显示“服务器”分支和工作树之间的差异。
  • git diff --ours显示“主”或“上游”分支与工作树之间的差异。

这可能与您期望的在合并时解决冲突的方式正好:)

git submodule update 和 git pull 的区别

从 fiji 目录调用 git supermodule update 和更改为子模块目录并执行 git pull 之间有什么区别?

大多数时候,您想要拥有子模块的最新最酷版本。您想要的是真正适合您的斐济状态的版本。因此,超级项目的提交还包含子模块目录的名称,以及这些子模块的当前提交。

现在

git submodule update

将子模块设置为与 fiji 提交一起保存的提交。

cd submoduleDirectory/  
git pull

实际上,为您提供了该子模块的最新最热门版本,该版本甚至可能无法与您当前的斐济状态进行编译。

如果我执行“git submodule update”,但在子中我位于实验分支上,这对超级项目无效,会发生什么?此时此子模块设置为对您当前斐济提交有效的状态,如果没有指定的分支上,将会分离模块所在的HEAD。这意味着您现在将子模块中的无名分支上(要恢复正常工作,您之前所在的子模块分支中不得有任何未提交的更改)