忽略Git子模块的新提交

93

背景

在Linux上使用Git 1.8.1.1。仓库如下所示:

master
  book

子模块是按以下方式创建的:

$ cd /path/to/master
$ git submodule add https://user@bitbucket.org/user/repo.git book

book 子模块是干净的:

$ cd /path/to/master/book/
$ git status
# On branch master
nothing to commit, working directory clean

问题

另一方面,主分支显示书籍子模块有“新提交”:

$ cd /path/to/master/
$ git status
# On branch master
# 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:   book (new commits)
#
no changes added to commit (use "git add" and/or "git commit -a")

Git应该完全忽略子模块目录,以便主仓库也保持干净:

$ cd /path/to/master/
$ git status
# On branch master
nothing to commit, working directory clean

尝试失败 #1 - 脏方法

根据这个答案,在文件master/.gitmodules内有以下内容:

[submodule "book"]
        path = book
        url = https://user@bitbucket.org/user/repo.git
        ignore = dirty

尝试失败#2-未跟踪

根据此答案,将master/.gitmodules更改为以下内容:

[submodule "book"]
        path = book
        url = https://user@bitbucket.org/user/repo.git
        ignore = untracked

第三次尝试失败 - showUntrackedFiles

根据这个答案,编辑master/.git/config如下:

[status]
   showUntrackedFiles = no

尝试失败 #4 - 忽略

将book目录添加到主要的忽略文件中:

$ cd /path/to/master/
$ echo book > .gitignore

第五次失败尝试-克隆

按照以下方式将book目录添加到主分支中:

$ cd /path/to/master/
$ rm -rf book
$ git clone https://user@bitbucket.org/user/repo.git book

问题

如何使book子模块位于主存储库下的自己的存储库目录中,同时让git忽略book子模块?也就是说,不应该显示以下内容:

#
#       modified:   book (new commits)
#

如何在主代码库中执行 git status 命令时抑制该消息?

一篇关于Git子模块陷阱的文章指出这是不适当的子模块使用方式吗?


3
如果你想将一个仓库链接到另一个特定版本的仓库,并对其进行跟踪,通常会使用子模块。但这似乎不是你想要做的。你只想在另一个仓库中使用一个仓库,而无需对其进行跟踪。那么就不要将其添加为子模块。 - Felix Kling
@FelixKling,如果您以这种方式添加这些存储库并将其推送到GitHub,那么它会创建一个链接而不是复制那些文件夹的内容吗? - Roman Bekkiev
@Roland:子模块只是一个带有对另一个存储库版本的引用的文件。一旦在本地仓库的副本中初始化它们,它们就会被实际存储库的内容所替代。 - Felix Kling
2
我认为你正在寻找“ignore = all”。 - greuze
1
在 Git 2.13 (2017 年第二季度) 中,您将能够考虑 git config submodule.<name>.active false。请参见下面的答案 - VonC
@VonC无法用于已经签出的子模块。 - Tobia
6个回答

123

只需运行:

$ git submodule update

这将会将子模块还原到旧的提交(在父仓库中指定),但不会使用子模块的最新版本更新父仓库。


9
不,它不是这样的,它不会改变现状。 - Ed Bishop
1
为什么OP想要不从book代码库获取最新的内容?我认为你的回答在这个情境下没有任何意义。 - Alexis Wilke
@AlexisWilke 如果书籍接口发生了重大变化,而OP没有时间在主代码库中进行更改怎么办? - Logman
你能在合并时解决冲突的同时完成这个任务吗? - David 天宇 Wong

63

如果要在超级仓库中包含另一个不需要被跟踪的仓库,请尝试以下操作:

$ cd /path/to/master/
$ rm -rf book
$ git clone https://user@bitbucket.org/user/repo.git book
$ git add book
$ echo "book" >> .gitignore

然后提交。

如链接的git submodule pitfalls article所述:

...父模块和子模块之间唯一的联系是记录在父模块提交中的子模块检出SHA值。

这意味着子模块不是通过其检出的分支或标签保存的,而总是由特定的提交保存;该提交(SHA)被保存到超级仓库(包含子模块的仓库)中,就像普通文本文件一样(当然会标记为此类引用)。

当您在子模块中检出不同的提交或对其进行新提交时,超级仓库将看到其检出的SHA已更改。这就是您从git status获得modified (new commits)行的时候。

为了消除这种情况,您可以选择:

  • git submodule update,将重置子模块以保存在超级存储库中当前保存的提交(有关详细信息,请参见git submodule手册); 或者
  • git add book && git commit 以将新的SHA保存到超级存储库中。

如评论中所述,考虑放弃book子模块:如果不需要将其状态作为超级存储库的一部分进行跟踪,则在超级存储库内克隆它。


4
哇,现在我明白为什么超级模块需要知道子模块的版本了。当然,这样做 git add book && git commit 是有道理的。我没有意识到 Git 实际上可以确保这两个仓库是同步的。 - Sergey Orshanskiy

24

你可以抑制两种变更通知(从Git 1.7.2开始)。

第一种是未跟踪的内容,当你对子模块进行更改但尚未提交时会出现此情况。父仓库会注意到这些更改,并且`git status`会相应地报告它们:

modified: book (untracked content)

您可以使用以下方式来抑制它们:

[submodule "book"]
    path = modules/media
    url = https://user@bitbucket.org/user/repo.git
    ignore = dirty

然而,一旦您提交了这些更改,父存储库将再次注意到并相应地报告它们:

modified:   book (new commits)

如果你想抑制这些内容,你需要忽略所有的更改。

[submodule "book"]
    path = book
    url = https://user@bitbucket.org/user/repo.git
    ignore = all

想象一下,我已经给所有的子模块添加了ignore = all选项。最终,一些模块有了新的提交并被推送。如果有人克隆超级仓库,它会处于子模块的旧状态还是会检出最新的状态? - FelikZ
使用命令git clone --recursive git@...,您将获得子模块的旧状态。要更新它们,您需要在克隆后执行类似git submodule foreach "git pull"的操作。 - greuze
1
不幸的是,ignore = all选项不能忽略子模块的新提交。我正在运行git版本1.7.1。有什么想法吗? - Romulus
我喜欢这种修复方法。 - GreatJohn
请执行以下代码: git submodule foreach --recursive "git pull --rebase" git submodule foreach --recursive "git checkout xxxBranch" - GreatJohn

11

Git 2.13(2017年第二季度)将添加另一种方式来包含一个子模块,这个子模块不需要由其父存储库进行跟踪。

在 OP 的情况下:

git config submodule.<name>.active false

请参见提交 1b614c0提交 1f8d711提交 bb62e0a提交 3e7eaed提交 a086f92(2017年3月17日)以及提交 ee92ab9提交 25b31f1提交 e7849a9提交 6dc9f01提交 5c2bd8b(2017年3月16日)由 Brandon Williams (mbrandonw)
(由Junio C Hamano -- gitster --提交 a93dcb0中合并)

submodule: 解耦url与子模块兴趣

目前,submodule.<name>.url配置选项用于确定用户是否对给定的子模块感兴趣。 在我们希望在不同的工作树中检出不同的子模块或选择哪些子模块感兴趣的更一般机制的世界中,这最终变得很麻烦。

在将来支持子模块的工作树的情况下,将存在多个工作树,每个工作树可能只需要检出子模块的子集。
URL(即子模块存储库的位置)在不同的工作树之间不应有差异。

用户更易于指定他们感兴趣的子模块组,而不是在其工作树中运行“git submodule init <path>”以检出每个他们想要检出的子模块。

为此


如何在现有项目中找到子模块的确切“<name>”? - ideasman42
@ideasman42 阅读.gitmodules中的配置应该会有所帮助:https://dev59.com/YGcs5IYBdhLWcg3wtmID#12641787 - VonC
啊,这只是来自于.git/config的值 -> [submodule "<name>"] - ideasman42
1
对我没用。这是我所做的: 1)使用--recursive进行git克隆; 2)将git配置设置为答案; 3)执行git checkout,git pull以检出最后一个子模块; 仍然得到“(new commits)”。 - Wu Baiquan
2
在给您发消息之前,我尝试了两种方法(使用现有的存储库以及新初始化的存储库),但对于这两种情况都没有起作用。 - Porcupine
显示剩余5条评论

2
Nevik Rehnel的回答对于你的问题肯定是正确的:我不想有一个子模块,那么我该如何摆脱这种情况?!。只有当你的master项目需要book子模块时,保留它是一个不错的姿态,因为这样其他检出你项目的用户就可以享受不需要运行任何特殊命令的待遇(嗯...虽然使用子模块还是有一些特殊命令要用的,但总体来说还是更容易管理)。在你的情况下,你会在book仓库中进行更改,并在某个时刻提交这些更改。这意味着你在该子模块中有新的提交,其中有一个新的SHA1引用。你需要在主目录中提交这些更改到主仓库中。
cd /path/to/master
git commit . -m "Update 'book' in master"

这将会更新master中的SHA1引用,使其与book存储库中最新版本相匹配。因此,此提交允许其他人在masterbook存储库的顶部检出所有内容。

因此,每当您更改子模块时,实际上会多出一个提交。如果您同时对master存储库中的某些文件进行更改,则这是半透明的,因为您将同时提交两个更改。


-6

运行

git submodule update 

在根级别。

1
只是为了任何人的参考。在我的情况下(和OP的情况?),这不会改变“git status”所说的。它仍然认为发生了更改。 - squarism
1
将他人的答案克隆是一种非常不良的做法。 - Maxim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接