如何追踪未被跟踪的内容?

166

请看下面的实线,这是我最初的问题。

我的本地文件夹中有一个未被跟踪的文件夹。当我运行 git status 命令时,会得到以下结果:

Changed but not updated:
modified:   vendor/plugins/open_flash_chart_2 (modified content, untracked content)

当我输入git add vendor/plugins/open_flash_chart_2,然后再试一次git status时,它仍然显示未跟踪。发生了什么事?
以下是我最近半小时的简单总结:
  • Discovered that my Github repo is not tracking my vendor/plugins/open_flash_chart_2 plugin. Specifically, there's no content and it's showing a green arrow on the folder icon.

  • Tried git submodule init

    No submodule mapping found in .gitmodules for path 'vendor/plugins/open_flash_chart_2'
    
  • Tried git submodule add git://github.com/korin/open_flash_chart_2_plugin.git vendor/plugins/open_flash_chart_2

    vendor/plugins/open_flash_chart_2 already exists in the index
    
  • git status

    modified: vendor/plugins/open_flash_chart_2 (untracked content)
    
  • Hunted for any file named .gitmodules in my repository/local directory but couldn't find one.

我该怎样才能让我的子模块正常工作,以便 git 能够正确地进行跟踪?


这可能与问题无关(我将其包含在内以防有用),但每次我键入 git commit -a 而不是我通常使用的 git commit -m "我的注释",它就会出现一个错误:

E325: ATTENTION
Found a swap file by the name ".git\.COMMIT-EDITMSG.swp"
         dated: Thu Nov 11 19:45:05 2010
     file name: c:/san/project/.git/COMMIT_EDITMSG
      modified: YES
     user name: San   host name: San-PC
    process ID: 4268
While opening file ".git\COMMIT_EDITMSG"
         dated: Thu Nov 11 20:56:09 2010
  NEWER than swap file!  
Swap file ".git\.COMMIT_EDITMSG.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:
Swap file ".git\.COMMIT_EDITMSG.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:

我对Github完全不了解,尽管试图阅读文档,但这些问题仍让我感到困惑。谢谢。


2
我对一些事情感到困惑。第一:为什么你一直说github?你所说的一切都听起来像是本地的(除了那个绿色箭头——我对那一点一无所知)。这是正确的吗,还是关于将更新推送到github的问题?第二:你是否真的做了任何事情来创建这个插件作为子模块?子模块是一个独立的git存储库。您需要单独创建它,然后将其添加到超级项目中。 - Cascabel
1
嗯,git status的输出表明确实有一个子模块...但你真的没有.gitmodules文件吗?老实说,如果这个插件有自己的仓库,并且你知道想要哪个版本,你可以从项目中删除该目录,确保.gitmodules中没有条目,然后进行子模块设置:git submodule addgit submodule update --init - Cascabel
Jefromi - 我实际上只提到了Github两次 - 第一次是因为在open_flash_chart_2的实际Github存储库中,绿色箭头出现在黄色文件夹图像的顶部。我很乐意编辑答案以使其更清晰。 - sscirrus
1
@sscirrus:你肯定应该有一个偏好,无论是子模块还是非子模块。如果这是一个你不打算工作但可能想要更新的外部项目,它应该是一个子模块。如果你不关心从其原始存储库获取更新,并可能想要自己处理源代码,则不应该将其设置为子模块。 - Cascabel
1
这个问题似乎纯粹是关于git子模块的。我删除了一些标签,因为这个问题与rails或github没有直接关系,它适用于所有git使用情况。而且tracking标签似乎用于“网站访问者跟踪”主题,所以也不适用。 - edgerunner
显示剩余8条评论
15个回答

247
你已将vendor/plugins/open_flash_chart_2作为“gitlink”条目添加,但从未将其定义为子模块。实际上,你正在使用git submodule使用的内部功能(gitlink条目),但你并没有使用子模块功能本身。
你可能做了这样的事情:
git clone git://github.com/korin/open_flash_chart_2_plugin.git vendor/plugins/open_flash_chart_2
git add vendor/plugins/open_flash_chart_2

最后这个命令是问题所在。目录vendor/plugins/open_flash_chart_2最初是独立的Git存储库。通常这样的子存储库会被忽略,但如果你告诉git add显式地添加它,那么它就会创建一个指向子存储库HEAD提交的gitlink条目,而不是添加目录内容。如果git add拒绝创建这种“半子模块”会更好。

普通目录在Git中表示为树对象;树对象提供名称和权限以及它们包含的对象(通常是其他树和blob对象,分别表示目录和文件)。子模块表示为“gitlink”条目;gitlink条目仅包含子模块HEAD提交的对象名称(哈希)。 gitlink的提交的“源存储库”在.gitmodules文件中指定(一旦初始化子模块,则在.git/config文件中也可以找到)。

您拥有的是指向特定提交的条目,没有记录该提交的源存储库。您可以通过将您的gitlink转换为正确的子模块或删除gitlink并替换为“普通”内容(纯文件和目录)来解决此问题。

将其转换为正确的子模块

要正确定义vendor/plugins/open_flash_chart_2作为子模块所缺少的唯一部分是一个.gitmodules文件。通常情况下(如果您还没有将其添加为裸gitlink条目),您只需使用git submodule add命令即可:

git submodule add git://github.com/korin/open_flash_chart_2_plugin.git vendor/plugins/open_flash_chart_2

正如你所发现的那样,如果路径已经存在于索引中,则这种方法将无法奏效。解决方案是暂时从索引中移除gitlink条目,然后添加子模块:

git rm --cached vendor/plugins/open_flash_chart_2
git submodule add git://github.com/korin/open_flash_chart_2_plugin.git vendor/plugins/open_flash_chart_2

这将使用您现有的子仓库(即它不会重新克隆源代码库)并暂存一个类似于以下内容的.gitmodules文件:

[submodule "vendor/plugins/open_flash_chart_2"]
    path = vendor/plugins/open_flash_chart_2
    url = git://github.com/korin/open_flash_chart_2_plugin.git vendor/plugins/open_flash_chart_2
它还将在您的主要存储库的.git/config中创建类似的条目(没有path设置)。
提交后,您将拥有一个适当的子模块。当您克隆存储库(或从GitHub推送并从那里克隆)时,您应该能够通过git submodule update --init重新初始化子模块。
用普通内容替换它
下一步假设您的子存储库(vendor/plugins/open_flash_chart_2)没有您想要保留的任何本地历史记录(即您关心的只是子存储库的当前工作树,而不是历史记录)。
如果您在子存储库中有重要的本地历史记录,那么在执行下面的第二个命令之前,应备份子存储库的.git目录。(还请考虑下面保留子存储库HEAD历史记录的git subtree示例)。
git rm --cached vendor/plugins/open_flash_chart_2
rm -rf vendor/plugins/open_flash_chart_2/.git # BACK THIS UP FIRST unless you are sure you have no local changes in it
git add vendor/plugins/open_flash_chart_2

这次添加目录时,它不是一个子仓库,所以文件将被正常添加。不幸的是,由于我们删除了.git目录,因此没有超级简单的方法可以与源代码仓库保持同步。

您可以考虑使用子树合并。这样做可以让您轻松地从源代码仓库中获取更改,同时在您的仓库中保持文件“平面化”(无子模块)。第三方git subtree命令是子树合并功能的一个不错的封装。

git rm --cached vendor/plugins/open_flash_chart_2
git commit -m'converting to subtree; please stand by'
mv vendor/plugins/open_flash_chart_2 ../ofc2.local
git subtree add --prefix=vendor/plugins/open_flash_chart_2 ../ofc2.local HEAD
#rm -rf ../ofc2.local # if HEAD was the only tip with local history

稍后:

git remote add ofc2 git://github.com/korin/open_flash_chart_2_plugin.git
git subtree pull --prefix=vendor/plugins/open_flash_chart_2 ofc2 master

git subtree push --prefix=vendor/plugins/open_flash_chart_2 git@github.com:me/my_ofc2_fork.git changes_for_pull_request

git subtree 还有一个 --squash 选项,可以让你避免将源代码库的历史记录合并到你的历史记录中,但仍然可以拉取上游的更改。


1
Chris,我刚刚尝试了rm -rf vendor/plugins/open_flash_chart_2/.git,但它显示“rm”未被识别。然后我尝试了git rm -rf vendor/plugins/open_flash_chart_2/.git,但它显示fatal: pathspec 'vendor/plugins/open_flash_chart_2/.git' did not match any files(但我可以在Windows资源管理器中找到它!)。 - sscirrus
3
我们在 聊天记录 中讨论了这个问题。提问者已经成功地删除了子仓库的 .git 目录,并以“平坦内容”选项(即第一个“Plain Content”选项)重新添加了文件。 - Chris Johnsen
1
这真的帮了我很多。前几天我不小心将一个包含.git目录的文件添加到我的git仓库中,然后git有点认为它是一个子模块,这导致我的git svn dcommits出现问题。如果可以的话,我会给你点赞三次。 - davidtbernal
想要指出的是,第三方插件subtree与子树合并不要混淆。它不是一个包装器。作者这么说的 :P - NebulaFox
我曾经遇到过类似的问题,但是我有很多需要作为子模块添加的仓库。最终我编写了一个脚本来自动化这个过程。可以在这里找到它:https://gist.github.com/landaire/25d231fca4b3af62d7cd - Lander
显示剩余2条评论

116

我刚遇到了同样的问题。原因是因为有一个子文件夹包含了一个“.git”文件夹。删除它后,Git就恢复正常了。


是的,这在我的AndroidStudio中发生过。当我试图创建一个git仓库时,该git仓库已经创建在/app文件夹中。谢谢。 - ZirconCode
我有一个在许多其他文件夹下创建的Angular CLI应用程序,而那个文件夹中有一个.git文件夹:/ 这才是真正的问题,而不是子模块的问题! - Pascal
这对我有用...我尝试了很多次git add,但什么也没发生。然后我删除了.git文件夹。 - Ninja
1
但是如果我仍然想要跟踪我的子文件夹怎么办?我应该怎么做? - code-8
保持相同的情况。仍然想要跟踪那个不幸包含了一个 .git 文件夹的子文件夹。在删除这个子文件夹中的 .git 文件夹后,它不再在我的主 .git 文件夹中被跟踪... .:( - sqp_125
简单而高效。谢谢 - Badhan Sen

14

什么是'/the/new/directories'?你怎么能够只复制另一个页面的示例而不给出解释呢? - Álvaro

6

我需要指出从Chris Johansen与OP的聊天(链接在一个回答中)中挖掘出来的内容:

git add vendor/plugins/open_flash_chart_2 # 将添加gitlink,内容将保持未跟踪状态

git add vendor/plugins/open_flash_chart_2/ # 注意斜杠!

第二种形式将不会添加gitlink,并且内容是可跟踪的。.git目录会方便地自动忽略。感谢Chris!


5
我经常使用Peter Lada提出的技巧,被称为“伪子模块”:
这在几种情况下非常有用(例如,我将所有Emacs配置都保存在一个存储库中,包括elpa/el-get包目录中所有git存储库的当前HEAD,因此当某些更新导致问题时,我可以轻松地回滚/前进到已知的工作版本)。
参考链接:http://debuggable.com/posts/git-fake-submodules:4b563ee4-f3cc-4061-967e-0e48cbdd56cb

5

我通过删除我的子文件夹中的.git文件来解决了这个问题。

  1. 首先从您的子文件夹中删除.git文件
  2. 然后运行此代码从git中删除子文件夹:git rm -rf --cached your_subfolder_name
  3. 最后使用git add .命令重新添加您的文件夹

3

我有一个大项目,里面有很多子模块,也遇到了同样的问题。根据Chris Johnsen 这里VonC 这里 的答案,我编写了一个简短的bash脚本,可以遍历所有现有的gitlink条目,并将它们添加为正确的子模块。

#!/bin/bash

# Read all submodules in current git
MODULES=`git ls-files --stage | grep 160000`

# Iterate through every submodule path
while read -r MOD; do
  # extract submodule path (split line at whitespace and take string with index 3)
  ARRIN=(${MOD})
  MODPATH=${ARRIN[3]}

  # grep module url from .git file in submodule path
  MODURL=`grep "url = " $MODPATH/.git/config`
  MODURL=${MODURL##*=}

  # echo path and url for information
  echo $MODPATH
  echo $MODURL

  # remove existing entry in submodule index
  git rm --cached $MODPATH
  # add new entry in submodule index
  git submodule add $MODURL $MODPATH
done <<< "$MODULES"

这个对我有帮助,希望对你有用。


3

我认为你应该阅读这篇文章,以了解一些关于子模块的知识。它写得很好,阅读起来也不需要太多时间。

http://progit.org/book/ch6-6.html


3
这对我来说完全没问题:
git update-index --skip-worktree 如果路径名无法使用,请尝试文件名。如果这对您也有效,请告诉我。
再见!

2

我曾经遇到过同样的问题,但这个讨论中并没有解决。

我也遇到了线程开头描述的子模块问题。

% git status          
# On branch master
# Changes not staged for commit:
#   modified:   bundle/taglist (untracked content)

观察diff,我看到hash值后面添加了-dirty:

再次阅读文档就解决了我的问题。 http://web.mit.edu/jhawk/mnt/spo/git/git-doc/user-manual.html 请查看“子模块的陷阱”一节。

原因是子模块中有更改或未被跟踪的内容。 我必须先进入子模块目录,执行“git add”和“git commit”以跟踪子模块中的所有内容。

Then "git status" on the master stated
% git commit
# On branch master
# Changes not staged for commit:
#   modified:   bundle/taglist (new commits)

现在,这个子模块的新HEAD可以提交到主模块。


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