Git子库

时间:2017-02-12 00:31:29

标签: git dependencies repository

我是一个小型固件团队的成员,我们使用私有Git服务器进行版本控制。我们的代码库通常包含用于平台特定代码的文件夹,多个平台使用的通用代码以及由我们开发的微处理器制造商提供的SDK。

目前我们的存储库以公共代码为中心;每个平台在存储库中都有一个文件夹。这至少会产生两个严重的后果;

  1. 当我们推送一个平台的更改时,对于共享相同公共代码的所有其他平台,它都是可见的。这会使提交历史记录与多个平台的版本混乱,并且过去导致我们对正在审查哪个平台的更改感到困惑。

  2. 在提交之前,需要对存储库中的所有平台验证对公共代码的更改,从而导致不必要的痛苦。 (有人昨天没有这样做,并且进行了更改,导致我们的几个旧平台无法构建。这个特殊的存储库中有5个平台)

  3. 我正在努力为每个平台建立一个存储库,以便我们可以定期更改公共代码并升级SDK,而不必强制更新和验证我们支持的所有平台。由于我们是一个五人团队,这些问题通常会在关键时刻发布,因此可以为我们节省大量不必要的脑损伤和时间。当然,困难的部分在于实施。

    现在我想象的是一个系统,每个平台都有自己的存储库,每个公共代码库都有自己的存储库,我们使用的每个SDK都有自己的存储库。平台存储库将链接或以其他方式引用它们用作“子存储库”的公共代码和SDK。

    我已经阅读了关于子模块的内容,但我认为它们会导致更多的问题而不是修复它们;最近我们不得不调试三年前的固件,这需要将我们的本地代码库重置为问题版本以进行静态分析。据我所知,子模块的本地版本与其所在的存储库分离,这意味着将存储库重置为旧提交将使子模块相对于存储库的其余部分保留在“未来”中。在调试旧代码的上下文中,这种行为是100%不可接受的。

    这是我要实现的项目的项目符号列表; (按重要性排序)

    1. 将平台特定代码从公共代码中删除,因此对公共代码和/或SDK的更改不会对其他平台产生无法预料的后果。

    2. 为每个平台,每个公共代码库和每个SDK创建新的存储库。

    3. 将远程存储库克隆到本地计算机应该是一个步骤;在平台构建之前,不应强迫新用户拉出每个子存储库。

      • 另外;恢复旧代码,包括用于构建任何给定平台版本XXX-YYY的公共代码和SDK,必须

      • 编辑:我最后一次“恢复”代码时,我使用硬重置来进行构建,我正在调试,软重置到比我更早的构建版本知道很好,但只有这样我的语法荧光笔中的Git插件才会显示已知好的和已知坏的对我的改变。

        顺便提一下,这个特殊的平台是单片的,这个问题不适用于它,但为了论证,我们会说它确实适用。

    4. 修改公共代码不应影响平台,直到平台的维护者拉入新的公共代码。 (我相信通过添加一个公共代码的标记提交而不是公共代码的主文件,可以使用子树)

    5. 只读子存储库是可接受的限制。 (即,无法在平台的存储库中修改子存储库,或者无法从平台的存储库中推送对子存储库的更改)

    6. SmartGit / HG支持是可取的,因为我们所有成员都使用它。

    7. 编写一次性任务脚本是可以接受的,但我不想污染那些使用Git工作的脚本的平台。

    8. 我也读过关于子树的内容,但此时我不确定他们是否会直觉地允许我想要的行为。我的主要问题是:Git是否支持这种功能?如果是,该功能是通过子树还是我还不知道的其他方法实现的?

2 个答案:

答案 0 :(得分:2)

我只是在这里鸣叫,因为我觉得@ VonC的答案并没有完全解释为什么子模块解决@ JacaByte的问题。

  

我认为他们会引起比他们解决的问题更多的问题;最近我们不得不调试三年前的固件,这需要将我们的本地代码库重置为问题版本以进行静态分析。据我所知,子模块的本地版本与它所在的存储库分离,这意味着将存储库重置为旧的提交将使子模块保留在" future"相对于存储库的其余部分。

这并非完全错误。但是,说子模块不允许您查看旧版本的代码库是不正确的。这种混淆是因为git checkout不更新子模块工作树,而是将该工作留给您(git submodule update --init --recursive将为您执行此操作)。

子模块是控制存储库依赖性的绝佳工具。实际上,它们具体您希望它们:关联特定的版本使用依赖的特定版本 您的代码。具体来说,一个"子模块"实际上只是一个文本文件,其中包含对应于子模块repo上的提交的SHA-1哈希值(Git存储有关.gitmodules中子模块远程的元信息,这就是它知道从何处获取子模块repo的副本)。

然而,使用子模块可能很棘手。它要求您对Git模型本身(提交和工作树/分段/ repo)以及对子模块系统本身的理解有很好的理解。但如果你确保人们知道他们正在做什么(如果这是非常那么大),你就可以避免自己在脚下射击。

您似乎非常关注自己回滚到旧版代码库的能力,@ VonC的答案似乎没有消除您的担忧,所以我在这里提供一个演练如何做到这一点:

我将以personal .dotfiles repo为例(我将Vim扩展作为子模块引入;在撰写本文时,HEADd9c0a797ad45a0d2fd92a07d3c3802528ed7b82a):

$ git clone https://github.com/sxlijin/.dotfiles dotfiles
Cloning into 'dotfiles'...
remote: Counting objects: 350, done.
remote: Compressing objects: 100% (31/31), done.
remote: Total 350 (delta 12), reused 0 (delta 0), pack-reused 318
Receiving objects: 100% (350/350), 86.61 KiB | 0 bytes/s, done.
Resolving deltas: 100% (176/176), done.
$ cd dotfiles/
$ git submodule update --init --recursive
Submodule 'bundle/jedi-vim' (http://github.com/davidhalter/jedi-vim) registered for path 'vim/bundle/jedi-vim'
Submodule 'bundle/nerdtree' (https://github.com/scrooloose/nerdtree.git) registered for path 'vim/bundle/nerdtree'
Submodule 'bundle/supertab' (https://github.com/ervandew/supertab.git) registered for path 'vim/bundle/supertab'
Submodule 'vim/bundle/vim-flake8' (https://github.com/nvie/vim-flake8.git) registered for path 'vim/bundle/vim-flake8'
Submodule 'bundle/vim-pathogen' (https://github.com/tpope/vim-pathogen.git) registered for path 'vim/bundle/vim-pathogen'
Cloning into '/home/pockets/dotfiles/vim/bundle/jedi-vim'...
warning: redirecting to https://github.com/davidhalter/jedi-vim/
Cloning into '/home/pockets/dotfiles/vim/bundle/nerdtree'...
Cloning into '/home/pockets/dotfiles/vim/bundle/supertab'...
Cloning into '/home/pockets/dotfiles/vim/bundle/vim-flake8'...
Cloning into '/home/pockets/dotfiles/vim/bundle/vim-pathogen'...
Submodule path 'vim/bundle/jedi-vim': checked out '8cf616b0887276e026aefdf68bc0311b83eec381'
Submodule 'jedi' (https://github.com/davidhalter/jedi.git) registered for path 'vim/bundle/jedi-vim/jedi'
Cloning into '/home/pockets/dotfiles/vim/bundle/jedi-vim/jedi'...
Submodule path 'vim/bundle/jedi-vim/jedi': checked out 'f05c0714c701ab784bd344aa063acd216fb45ec0'
Submodule path 'vim/bundle/nerdtree': checked out '281701021c5001332a862da80175bf585d24e2e8'
Submodule path 'vim/bundle/supertab': checked out 'cdaa5c27c5a7f8b08a43d0b2e65929512299e33a'
Submodule path 'vim/bundle/vim-flake8': checked out '91818a7d5f5a0af5139e9adfedc9d00fa963e699'
Submodule path 'vim/bundle/vim-pathogen': checked out '7ba2e1b67a8f8bcbafedaf6763580390dfd93436'

最后一个命令git submodule update --init --recursive查看了HEAD中存储的子模块哈希值,并更新了我的工作树(将它们更新为各自最近的提交repos;那个git submodule update --remote),在相应的路径上添加相应存储库的内容,递归地这样做(所以如果我的任何子模块都有子模块,他们这样做,那些存储库的内容也会得到添加到我的工作树中。)

现在,碰巧我在HEAD~2更新了我的Vim插件:

$ git show HEAD~2 -- vim/bundle/*
commit 27bfe76851991026bd026b4bf2ab10d6ecbc6f74
Author: First Last <first.last@email.domain>
Date:   Thu Feb 2 13:33:30 2017 -0600

    update dependencies

diff --git a/vim/bundle/jedi-vim b/vim/bundle/jedi-vim
index f191ccd..8cf616b 160000
--- a/vim/bundle/jedi-vim
+++ b/vim/bundle/jedi-vim
@@ -1 +1 @@
-Subproject commit f191ccd6fb7f3bc2272a34d6230487caf64face7
+Subproject commit 8cf616b0887276e026aefdf68bc0311b83eec381
diff --git a/vim/bundle/nerdtree b/vim/bundle/nerdtree
index eee431d..2817010 160000
--- a/vim/bundle/nerdtree
+++ b/vim/bundle/nerdtree
@@ -1 +1 @@
-Subproject commit eee431dbd44111c858c6d33ffd366cae1f17f8b3
+Subproject commit 281701021c5001332a862da80175bf585d24e2e8
diff --git a/vim/bundle/supertab b/vim/bundle/supertab
index 6651177..cdaa5c2 160000
--- a/vim/bundle/supertab
+++ b/vim/bundle/supertab
@@ -1 +1 @@
-Subproject commit 66511772a430a5eaad7f7d03dbb02e8f33c4a641
+Subproject commit cdaa5c27c5a7f8b08a43d0b2e65929512299e33a

让我们说现在我的Vim插件似乎很奇怪,我怀疑上面的提交是造成这种奇怪的原因,所以我想在我更新之前将我的插件回滚到它们之前的任何内容它们。

$ git checkout -b testing HEAD~2^
M       vim/bundle/jedi-vim
M       vim/bundle/nerdtree
M       vim/bundle/supertab
Switched to a new branch 'testing'
$ git status
On branch testing
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   vim/bundle/jedi-vim (new commits)
        modified:   vim/bundle/nerdtree (new commits)
        modified:   vim/bundle/supertab (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

好吧,现在的东西似乎有点奇怪。当我执行此结帐时,我的工作树中没有任何更改,所以结帐似乎是对我的工作树引入了更改?这里发生了什么?

$ git diff
diff --git a/vim/bundle/jedi-vim b/vim/bundle/jedi-vim
index f191ccd..8cf616b 160000
--- a/vim/bundle/jedi-vim
+++ b/vim/bundle/jedi-vim
@@ -1 +1 @@
-Subproject commit f191ccd6fb7f3bc2272a34d6230487caf64face7
+Subproject commit 8cf616b0887276e026aefdf68bc0311b83eec381
diff --git a/vim/bundle/nerdtree b/vim/bundle/nerdtree
index eee431d..2817010 160000
--- a/vim/bundle/nerdtree
+++ b/vim/bundle/nerdtree
@@ -1 +1 @@
-Subproject commit eee431dbd44111c858c6d33ffd366cae1f17f8b3
+Subproject commit 281701021c5001332a862da80175bf585d24e2e8
diff --git a/vim/bundle/supertab b/vim/bundle/supertab
index 6651177..cdaa5c2 160000
--- a/vim/bundle/supertab
+++ b/vim/bundle/supertab
@@ -1 +1 @@
-Subproject commit 66511772a430a5eaad7f7d03dbb02e8f33c4a641
+Subproject commit cdaa5c27c5a7f8b08a43d0b2e65929512299e33a
嗯,好的,所以这很有意思。出于某种原因,git diff表示在我当前工作树中检出的子模块的版本不匹配 - 但这个差异看起来像{{1> 我在上面做了。我想知道git show ...

中实际有哪些子模块
HEAD

啊哈!我们去了 - $ git ls-tree HEAD -- vim/bundle/ 160000 commit f191ccd6fb7f3bc2272a34d6230487caf64face7 vim/bundle/jedi-vim 160000 commit eee431dbd44111c858c6d33ffd366cae1f17f8b3 vim/bundle/nerdtree 160000 commit 66511772a430a5eaad7f7d03dbb02e8f33c4a641 vim/bundle/supertab 160000 commit 91818a7d5f5a0af5139e9adfedc9d00fa963e699 vim/bundle/vim-flake8 160000 commit 7ba2e1b67a8f8bcbafedaf6763580390dfd93436 vim/bundle/vim-pathogen 只是没有更新工作树中子模块的版本!不过,Git本身仍然知道应该检查这些子模块的哈希值。结果发现了一个可以为你完成此任务的命令:

git checkout

单独解决您的疑虑:

  1.   

    将平台特定代码从公共代码中删除,以便更改为   公共代码和/或SDK不会产生无法预料的后果   其他平台。

    是的。子模块。

  2.   

    为每个平台创建新的存储库   通用代码库和每个SDK。

    这将取决于批次如何构建您当前的代码库。 $ git submodule update --init --recursive Submodule path 'vim/bundle/jedi-vim': checked out 'f191ccd6fb7f3bc2272a34d6230487caf64face7' Submodule path 'vim/bundle/jedi-vim/jedi': checked out '2ba78ab725f1e02dfef8bc50b0204cf656e8ee23' Submodule path 'vim/bundle/nerdtree': checked out 'eee431dbd44111c858c6d33ffd366cae1f17f8b3' Submodule path 'vim/bundle/supertab': checked out '66511772a430a5eaad7f7d03dbb02e8f33c4a641' 可能有你想要的东西(具体来说git subtree可以让你将子树中的文件提取到一个单独的Git仓库中,充满了提交历史记录,但我不知道它如何与您似乎正在描述的大型和旧式仓库一起工作 - 有关详细信息,请参阅git subtree split

  3.   

    将远程存储库克隆到   本地机器应该是一步到位的过程;新用户不应该   在平台构建之前被迫拉动每个子存储库。

    不。子模块按设计不跟踪子存储库的内容:这是子存储库的工作。他们所做的只是保留指向子仓库中特定提交的指针。

  4.   

    另外;恢复旧代码,包括通用代码和SDK   用于构建任何给定平台的版本XXX-YYY的必须   有可能。修改公共代码不应该影响   直到平台的维护者拉入新的平台   常用代码。 (我相信通过添加一个子树可以实现这一点   公共代码的标记提交而不是公共代码   主)

    子模块通过设计实现。这就是为什么他们指向特定的提交而不是远程。

  5.   

    只读子存储库是可接受的限制。   (即子库不能在平台中修改   无法推送存储库或对子存储库的更改   平台的存储库)

    子模块通常应被视为只读子存储库。可以从子模块推送更新,但会增加用户的开销,以确保他们不会搞砸他们正在使用的子模块的版本。

  6.   

    所有人都希望获得SmartGit / HG支持   但是我们的一个成员使用它。

    这里不保证。您可能需要联系所有3个开发社区(Git,SmartGit,Mercurial)来解决这个问题。

  7.   

    编写一次性任务的脚本是   可以接受,但我不想用脚本污染平台   做Git的工作吧。

    取决于你说话的复杂程度。我已经在上面看到,检查旧版本的代码只有两个命令:man git subtreecheckout,但它并不清楚您要求的是什么。

答案 1 :(得分:1)

  

我认为他们会引起比他们解决的问题更多的问题;最近我们不得不调试三年前的固件,这需要将我们的本地代码库重置为问题版本以进行静态分析。据我所知,子模块的本地版本与其所在的存储库分离,这意味着将存储库重置为旧提交将使子模块相对于存储库的其余部分保留在“未来”中。

绝对不是。
Submodule 完全您需要的内容。

如果您需要将父级仓库重置为过去的提交,它还将子模块根文件夹(称为gitlink)重置为正确的SHA1(已记录的一个)当时)。那是what a gitlink is for

clone --recursive将在一个命令中克隆父repo及其子模块。

如果需要,您可以configure a submodule to follow the latest commits of a branch

你可以从你的父回购both said parent repo and its submodules, again in one command推送。

相关问题