繁体   English   中英

添加 Git 子模块时如何指定分支/标签?

[英]How can I specify a branch/tag when adding a Git submodule?

git submodule add -b如何工作?

添加具有特定分支的子模块后,新的克隆存储库(在git submodule update --init之后)将处于特定提交,而不是分支本身(子模块上的git status显示“当前不在任何分支上”)。

我在.gitmodules.git/config上找不到关于子模块分支或任何特定提交的任何信息,那么 Git 是如何弄清楚的呢?

另外,是否可以指定标签而不是分支?

我使用的是 1.6.5.2 版。

注意:Git 1.8.2 添加了跟踪分支的可能性。 请参阅下面的一些答案。


习惯这一点有点令人困惑,但子模块不在分支上。 就像您说的那样,它们只是指向子模块存储库的特定提交的指针。

这意味着,当其他人检出您的存储库或提取您的代码并执行 git submodule update 时,子模块将检出到该特定提交。

这对于不经常更改的子模块非常有用,因为项目中的每个人都可以在同一个提交中拥有子模块。

如果要将子模块移动到特定标签:

cd submodule_directory
git checkout v1.0
cd ..
git add submodule_directory
git commit -m "moved submodule to v1.0"
git push

然后,另一个想要将 submodule_directory 更改为该标记的开发人员执行此操作

git pull
git submodule update --init

git pull提交其子模块目录指向的更改。 git submodule update实际上合并到新代码中。

我想在这里添加一个答案,它实际上只是其他答案的集合,但我认为它可能更完整。

当你有这两件事时,你就知道你有一个 Git 子模块。

  1. 你的.gitmodules有一个像这样的条目:

     [submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git
  2. 您的 Git 存储库中有一个子模块对象(在本示例中名为 SubmoduleTestRepo)。 GitHub 将这些显示为“子模块”对象。 或者从命令行执行git submodule status Git 子模块对象是特殊类型的 Git 对象,它们保存特定提交的 SHA 信息。

    每当您执行git submodule update ,它都会使用提交中的内容填充您的子模块。 由于.gitmodules中的信息,它知道在哪里可以找到提交。

    现在, -b所做的就是在.gitmodules文件中添加一行。 因此,按照相同的示例,它看起来像这样:

     [submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git branch = master

    注意: .gitmodules文件只支持分支名称,不支持 SHA 和 TAG! (取而代之的是,可以使用“ git add . ”来跟踪和更新每个模块的分支提交,例如git add ./SubmoduleTestRepo ,并且您不需要每次都更改.gitmodules文件)

    子模块对象仍然指向特定的提交。 -b选项为您购买的唯一功能是能够根据 Vogella 的回答向您的更新添加--remote标志:

     git submodule update --remote

    它不是将子模块的内容填充到子模块指向的提交,而是用主分支上的最新提交替换该提交,然后用该提交填充子模块。 这可以通过 djacobs7 answer 分两步完成。 由于您现在已经更新了子模块对象指向的提交,因此您必须将更改的子模块对象提交到您的 Git 存储库中。

    git submodule add -b并不是通过分支使所有内容保持最新的神奇方式。 它只是在.gitmodules文件中添加有关分支的信息,并为您提供在填充之前将子模块对象更新为指定分支的最新提交的选项。

(Git 2.22,Q2 2019,引入了git submodule set-branch --branch aBranch -- <submodule_path>

请注意,如果您有一个尚未跟踪分支的现有子模块,那么(如果您有 git 1.8.2+ ):

  • 确保父仓库知道它的子模块现在跟踪一个分支:

     cd /path/to/your/parent/repo git config -f .gitmodules submodule.<path>.branch <branch>
  • 确保您的子模块实际上是该分支的最新版本:

     cd path/to/your/submodule git checkout -b branch --track origin/branch # if the master branch already exist: git branch -u origin/master master

('origin' 是上游远程存储库的名称,子模块已从中克隆。
该子模块中的git remote -v将显示它。 通常,它是“起源”)

  • 不要忘记在父仓库中记录子模块的新状态:

     cd /path/to/your/parent/repo git add path/to/your/submodule git commit -m "Make submodule tracking a branch"
  • 该子模块的后续更新必须使用--remote选项:

     # update your submodule # --remote will also fetch and ensure that # the latest commit from the branch is used git submodule update --remote # to avoid fetching use git submodule update --remote --no-fetch

请注意,在Git 2.10+ (2016 年第三季度)中,您可以使用 ' . ' 作为分支名称:

分支的submodule.<name>.branch.gitmodules记录为submodule.<name>.branch .gitmodules用于update --remote
的特殊值. 用于指示子模块中的分支名称应与当前存储库中的当前分支名称相同

但是, 正如LubosD 所评论那样

使用git checkout ,如果要遵循的分支名称是“ . ”,它将杀死您未提交的工作!
请改用git switch

这意味着 Git 2.23(2019 年 8 月)或更高版本。

参见“git checkout混淆


如果要更新分支后的所有子模块:

    git submodule update --recursive --remote

请注意,对于每个更新的子模块,结果几乎总是一个分离的 HEAD ,正如Dan Cameron他的回答中指出的那样。

Clintm 在评论中指出,如果您运行git submodule update --remote并且生成的 sha1 与子模块当前所在的分支相同,它不会做任何事情并使子模块仍然“在该分支上”并且不是处于分离的头部状态。)

为了确保分支实际被检出(并且不会修改代表父存储库子模块的特殊条目的 SHA1),他建议:

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch $branch'

每个子模块仍将引用相同的 SHA1,但如果您确实进行了新提交,您将能够推送它们,因为它们将被您希望子模块跟踪的分支引用。
在子模块中推送之后,不要忘记返回父存储库,为那些修改过的子模块添加、提交和推送新的 SHA1。

请注意Alexander Pogrebnyak 在评论中推荐的$toplevel的使用。
$toplevel于 2010 年 5 月在 git1.7.2 中引入: commit f030c96

它包含顶级目录的绝对路径( .gitmodules所在的.gitmodules )。

dtmland 在评论中补充道:

foreach 脚本将无法检出未遵循分支的子模块。
但是,此命令为您提供:

 git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git switch $branch' –

相同的命令但更易于阅读:

git submodule foreach -q --recursive \
    'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \
     [ "$branch" = "" ] && \
     git checkout master || git switch $branch' –
  

umläute 在评论中使用简化版本改进了dtmland的命令:

git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

多行:

git submodule foreach -q --recursive \
  'git switch \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

在 Git 2.26(2020 年第一季度)之前,被告知在子模块中递归获取更新的获取不可避免地会产生大量输出,并且很难发现错误消息。

该命令已被教导枚举在操作结束时出现错误的子模块

请参阅Emily Shaffer ( nasamuffin ) 提交的 0222540 (2020 年 1 月 16 日)
(由Junio C gitster -- gitster --提交 b5c71cc 中合并,2020 年 2 月 5 日)

fetch : 强调子模块获取过程中的失败

签字人:Emily Shaffer

在有许多子模块时子模块获取失败的情况下,如果多个获取回退到fetch-by-oid上,则单独失败的子模块获取的错误会被其他子模块的活动所fetch-by-oid
晚点调用失败,以便用户知道出了什么问题,以及哪里出了问题

由于fetch_finish()仅由run_processes_parallel,同步run_processes_parallel,因此不需要围绕submodules_with_errors互斥。


请注意,在 Git 2.28(2020 年第三季度)中,重写部分脚本化的“git submodule”Porcelain 命令继续; 这次轮到“ git submodule set-branch ”子命令了。

请参阅Shourya Shukla ( periperidip ) 的commit 2964d6e (02 Jun 2020 )
(由Junio C gitster合并-- gitster -- in commit 1046282 ,2020 年 6 月 25 日)

submodule :从 shell 到 C 的端口子命令“set-branch”

导师:Christian Couder
导师:Kaartic Sivaraam
帮助:Denton Liu
帮助者:Eric Sunshine
帮助者:Đoàn Trần Công Danh
签字人:Shourya Shukla

将子模块子命令 'set-branch' 转换为内置命令并通过git submodule.sh调用它。

Git 1.8.2 添加了跟踪分支的可能性。

# add submodule to track branch_name branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

另请参阅Git 子模块

我如何使用 Git 子模块的示例。

  1. 创建一个新的存储库
  2. 然后将另一个存储库克隆为子模块
  3. 然后我们让该子模块使用一个名为 V3.1.2 的标签
  4. 然后我们承诺。

这看起来有点像这样:

git init 
vi README
git add README
git commit 
git submodule add git://github.com/XXXXX/xxx.yyyy.git stm32_std_lib
git status

git submodule init
git submodule update

cd stm32_std_lib/
git reset --hard V3.1.2 
cd ..
git commit -a

git submodule status 

也许它有帮助(即使我使用标签而不是分支)?

根据我的经验,无论是否正确添加和跟踪子模块(即 @djacobs7 和 @Johnny Z 答案),切换超级项目中的分支或将来的结帐仍会导致子模块的 HEAD 分离。

并且可以使用git submodule foreach代替手动或通过脚本手动检出正确的分支。

这将检查分支属性的子模块配置文件并检出设置分支。

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel.gitmodules submodule.$name.branch)"; git checkout $branch'

Git 子模块有点奇怪——它们总是处于“分离头”模式——它们不会像你期望的那样更新到分支上的最新提交。

不过,当你考虑它时,这确实是有道理的。 假设我使用子模块bar创建存储库foo 我推送我的更改并告诉您从存储库foo检查提交 a7402be 。

然后想象有人在您可以进行克隆之前提交了对存储库的更改。

当您从存储库foo检出提交 a7402be 时,您希望获得与我推送的相同的代码。 这就是为什么子模块在您明确告诉它们然后进行新提交之前不会更新的原因。

我个人认为子模块是 Git 中最令人困惑的部分。 有很多地方可以比我更好地解释子模块。 我推荐 Scott Chacon 的Pro Git

现有答案缺少第二步,并且细节过多。

要切换现有子模块以跟踪新的远程 url 和/或新分支:

  1. .gitmodules中编辑事实来源。

例如,从

[submodule "api"]
    path = api
    url = https://github.com/<original_repo>/api.git

[submodule "api"]
    path = api
    url = https://github.com/<another_repo>/api.git
    branch = work-in-progress
  1. git submodule sync :更新.git/modules中 git 缓存的子模块的描述,来自.gitmodules中指定的刚刚编辑的真实来源。

  2. git submodule update --init --recursive --remote :更新工作副本中签出的子模块。

  3. 提交更改。

要为子模块切换分支(假设您已经将子模块作为存储库的一部分):

  • cd到包含子模块的存储库的根目录
  • 打开.gitmodules进行编辑
  • path = ...url = ...下面添加一行,表示branch = your-branch ,对于每个子模块; 保存文件.gitmodules
  • 然后不改变目录做$ git submodule update --remote

...这应该为每个修改后的子模块拉入指定分支上的最新提交。

我的 .gitconfig 文件中有这个。 它仍然是一个草案,但到目前为止证明是有用的。 它帮助我始终将子模块重新附加到他们的分支。

[alias]

######################
#
#Submodules aliases
#
######################


#git sm-trackbranch : places all submodules on their respective branch specified in .gitmodules
#This works if submodules are configured to track a branch, i.e if .gitmodules looks like :
#[submodule "my-submodule"]
#   path = my-submodule
#   url = git@wherever.you.like/my-submodule.git
#   branch = my-branch
sm-trackbranch = "! git submodule foreach -q --recursive 'branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; git checkout $branch'"

#sm-pullrebase :
# - pull --rebase on the master repo
# - sm-trackbranch on every submodule
# - pull --rebase on each submodule
#
# Important note :
#- have a clean master repo and subrepos before doing this !
#- this is *not* equivalent to getting the last committed 
#  master repo + its submodules: if some submodules are tracking branches 
#  that have evolved since the last commit in the master repo,
#  they will be using those more recent commits !
#
#  (Note : On the contrary, git submodule update will stick 
#to the last committed SHA1 in the master repo)
#
sm-pullrebase = "! git pull --rebase; git submodule update; git sm-trackbranch ; git submodule foreach 'git pull --rebase' "

# git sm-diff will diff the master repo *and* its submodules
sm-diff = "! git diff && git submodule foreach 'git diff' "

#git sm-push will ask to push also submodules
sm-push = push --recurse-submodules=on-demand

#git alias : list all aliases
#useful in order to learn git syntax
alias = "!git config -l | grep alias | cut -c 7-"

我们使用Quack从另一个 Git 存储库中提取特定模块。 我们需要在没有提供的存储库的整个代码库的情况下提取代码——我们需要从那个巨大的存储库中获取一个非常具体的模块/文件,并且每次运行更新时都应该更新。

所以我们是这样实现的:

创建配置

name: Project Name

modules:
  local/path:
    repository: https://github.com/<username>/<repo>.git
    path: repo/path
    branch: dev
  other/local/path/filename.txt:
    repository: https://github.com/<username>/<repo>.git
    hexsha: 9e3e9642cfea36f4ae216d27df100134920143b9
    path: repo/path/filename.txt

profiles:
  init:
    tasks: ['modules']

通过上述配置,它从提供的 GitHub 存储库中创建一个目录,如第一个模块配置中指定的那样,另一个是从给定的存储库中拉取并创建一个文件。

其他开发者只需要运行

$ quack

它从上述配置中提取代码。

为子模块选择分支的唯一效果是,每当您在git submodule update命令行中传递--remote选项时,Git 都会以分离的 HEAD模式--checkout (如果选择了默认的--checkout行为)最新的提交选定的远程分支。

如果您使用子模块的浅层克隆,则在对 Git 子模块使用此远程分支跟踪功能时必须特别小心。 您在子模块设置中为此目的选择的分支不是将在git submodule update --remote期间克隆的git submodule update --remote 如果你还传递了--depth参数并且你没有告诉 Git 你想要克隆哪个分支——实际上你不能git submodule update命令行中!! -- ,当显式的--branch参数丢失时,它将隐式地表现得像git clone --single-branchgit-clone(1)文档中解释的那样,因此它只会克隆主分支

不出所料,在git submodule update命令执行克隆阶段后,它最终会尝试检查您之前为子模块设置的远程分支的最新提交,如果这不是主要分支,则为不是本地浅层克隆的一部分,因此它会失败

致命:需要一次修订

无法在子模块路径“mySubmodule”中找到当前来源/ NotThePrimaryBranch修订版

git submodule add -b develop --name branch-name -- https://branch.git

使用以下命令

添加子模块(分支分支)

git submodule add -b stage git@github.optum.com:orgname/${reponame}.git

更新子模块(分支-分支)

######Clone########

> git clone -b master --single-branch --recurse-submodules git@github.com:orgname/project.git  
or  
> git clone -b stage --single-branch --recurse-submodules git@github.com:orgname/project.git

######Update#######
> git submodule update  --remote (only for remote branch -ie master) 
or 
> git submodule update --recursive --remote

> git submodule update --init --recursive (for remaining branchs)

if you get fatal need single revision error then use below commands:-

before:-

*** stage
  remotes/origin/stage**

git branch -a

git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/{branch name}
ex:- git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/stage

after:-
*** stage
  remotes/origin/HEAD -> origin/stage
  remotes/origin/stage**

then 

> git reset --hard

#hard reset revisions#

> git submodule foreach git reset --hard origin/develop

> git submodule foreach git pull origin develop

在提交并相应地推送之后.. 现在子模块将得到更新。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM