Git没有提取被忽略的跟踪文件

时间:2017-04-14 05:25:27

标签: git mingw gitignore

这个问题几乎与如何阻止Git跟踪被忽略文件的常见问题相反。在这种情况下,我想跟踪它们,而不是忽略它们。

我有一个.gitignore文件,其中包含以下行:

**/*.exe

大多数情况下,.exe文件是构建的产品,并且将被忽略(此项目托管在MinGW和Cygwin的组合上,因此二进制文件在Windows上运行。)

但是,此忽略规则有例外。我在源代码树中添加了一些.exe个文件。据我了解,.gitignore不适用于跟踪文件(索引中的文件)。

但是,当我克隆我的存储库时,不会获取.exe个文件。

如果我在我添加的原始存储库中的文件上执行git status,我会得到:

$ git status program.exe On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean

该文件也存在于工作树中:

$ ls -l program.exe -rwxrwx---+ 1 abc xyz 23040 Mar 20 15:35 program.exe

$ git log program.exe

commit 412fd58b5a11bf6a40f661109e71f2c0026c1643 Author: abc <abc@xyz.com> Date: Sat Apr 1 02:21:40 2017 -0700

cleanup

commit b0a2efd4dc17b70d046c1e7d78e3142cf29410ba Author: abc <abc@xyz.com> Date: Mon Mar 20 18:41:00 2017 -0700

Initial version

我已将提交推送到另一台服务器上的裸存储库。我可以在裸存储库中找到与最新签入相对应的blob:

MyProject.git/objects/41/2fd58b5a11bf6a40f661109e71f2c0026c1643

显然它正在被追踪。但是当我克隆存储库时,它不会出现在工作树中。 在克隆的存储库

$ git status program.exe On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean

$ ls -l program.exe ls: cannot access 'program.exe': No such file or directory

我没有使用assume-unchanged等。

  1. 被忽略但被跟踪的文件在其他存储库中获取时仍被忽略?

  2. 即使匹配.gitignore,如何强制取出它们?

  3. 您是否需要将其排除在匹配.gitignore之外才能获取?

  4. $ git --version git version 2.12.0.windows.1

    编辑:请记住,在将跟踪文件添加到.gitignore之后,我不会尝试忽略它们。我正在尝试获取跟踪和提交的文件,尽管它们匹配.gitignore

2 个答案:

答案 0 :(得分:1)

TL; DR:我认为这里有关于跟踪意味着

的重要见解

在我的原始答案和下面的大量讨论之间,我意识到我认为不明显的事情。当我第一次使用Git时,这对我来说当然不是很明显(可能是几个月,如果不是几年)。这里有两个部分:

  • 在Git中,跟踪表示索引中的

  • 但是,每次检查某些特定提交时,索引(您将要进行的下一次提交)都会更改,例如{。}}

    < / LI>

这意味着是否跟踪文件是相对的,而不是绝对的。文件 F 可能会在git checkout otherbranch后跟踪,然后在git checkout branch1后跟踪。它可能已在分支git checkout branch2上的过去提交中被跟踪,现在已在分支master上未跟踪。如果文件未被跟踪,但过去 被跟踪, 当前在工作树中,则可能非常困难弄清楚发生了什么。该文件不会出现在新克隆中,即使它在历史记录中。

(原文,完整答案在这里。)

  

但是,当我克隆我的存储库时,不会获取master个文件。

.exe操作无法获取任何文件。相反,它会提取提交。现在,提交包含文件是真的,所以这似乎是一个毫无意义的迂腐,但它对你的问题至关重要,事实上几乎所有的Git,所以它真的很重要。 Git并不关心文件; Git就是关于提交的。

提交本身构成了历史。每个提交都包含一些文件集,但也有一个指向前一个提交的指针:&#34;这就是我们现在拥有的。这是我们之前提交的哈希ID。&#34;我们称之为提交的。父提交也有自己的父级。这个向后看的链存储库中的历史记录。

git clone这样的分支名称是Git记录该分支的当前哈希ID的方式。 Git从最近的提交开始,使用分支名称;然后Git在需要时向后工作,获得较旧(父)的提交,并按要求提交更老的(祖父母,曾祖父母等)提交。

运行master复制分支名称及其提交,该提交的父级以及父级的父级,依此类推;这样你就得到了所有的历史。每次提交都会带有使用该提交存储的文件,因此,一旦完成所有提交,您不仅拥有所有当前文件,还拥有所有以前的当前 parent-commit文件,以及每个早期文件一直回到第一次提交。但是所有这些文件都隐藏在一个秘密的,只有Git的格式中,除了Git之外没什么好处。不过,那是git clone复制的内容。

当然,为了让Git实际上做任何有用的事情,我们需要一些实际有用的形式的文件。所以Git在这个提交历史记录中添加了一些东西 - 但它不是克隆的东西; 以及那些问题进来的地方。

存储库中的内容

在一个有用的(即非git clone)存储库中,我们不仅需要所有提交和各种分支名称来记住它们最新的哈希ID,我们还需要一个工作树。工作树是我们可以处理实际文件的地方。根据需要,它们以树形结构排列,具有顶级文件和目录,以及目录中的更多文件和子目录。 (因此名称&#34;工作树&#34;:它是工作表单文件的树。)

Git还引发了另一件事,Git称之为索引。索引的简短描述是您构建 next 提交的位置。如果你从未对自己的存储库进行任何更改,那么这个索引会妨碍你,但是Git仍然会强迫你知道它。如果您执行进行更改,则索引至关重要,因为进行更改的方式是修改工作树中的内容,然后使用--bare进行复制那些修改回到索引中,以便它们分阶段用于下一次提交。然后,当您运行git add进行提交时,Git会复制索引 -ie中的所有内容,以及之前存在的所有旧内容,但无论你用git commit新东西替换成新的东西 -

知道这一点非常重要:索引会跟踪工作树中的内容。事实上,这正是&#34;跟踪&#34;表示:跟踪表示索引中的但索引也是将在下一次提交中的内容,因此它开始匹配当前提交中的内容

您可以 - 并且通常执行 - 在工作树中,有意识地 跟踪的文件。例如,您的git add文件故意未跟踪。未跟踪意味着他们不在索引中。这意味着它们不在当前提交中, 1 ,现在我们可以看到存在问题。

1 也就是说,它们不在当前的提交中,除非索引是&#34;脏&#34;因此需要写出新的提交。同样,这就是你首先提出新提交的方法:你修改工作树中的东西 - 比如修改文件,添加全新文件,或删除现有文件 - 然后你复制那些&#34;脏& #34;工作树文件到索引中,&#34;弄脏&#34;指数。然后,您*.exe进行提交。新提交的父级是当前提交的内容,其文件是索引中的任何内容。然后Git将新提交的哈希ID写入分支名称,新提交现在是历史记录的一部分,永远保存。

异议:&#34;我可以找到blob&#34;

你提到过:

  

我可以在裸存储库中找到与最新签入相对应的blob:git commit

这意味着该文件已在某个时间提交 。它位于某些历史提交中。这并不意味着该文件位于MyProject.git/objects/41/2fd58b5a11bf6a40f661109e71f2c0026c1643之类的分支上的最新提交中。存储库具有Git内部(压缩对象)格式, 每个文件的版本。并且,您可以并且经常在您的工作树中拥有一个不在索引中但不在当前提交中的文件。该文件可能与您过去提交的文件匹配。

因此,存储库中文件的存在并不意味着它在某个特定分支上的最新提交中。它确实意味着您可以提取历史文件。例如,鉴于上述情况,您可以:

master

随时将其提取到git show 412fd58b5a11bf6a40f661109e71f2c0026c1643 > foo.exe 。如果您知道提交哈希和路径,也可以使用它:

foo.exe

并且如果提交具有名称(例如分支或标记名称):

git show 1234567:path/to/foo.exe > foo.exe

可以使用这种方法来提取历史文件,但这显然有些痛苦。

获取所有提交后git show name:path/to/foo.exe > foo.exe 执行的操作

如上所述,git clone首先复制提交和分支名称。事实上,默认情况下,它将这些分支名称重命名为 Git所称的&#34;远程跟踪分支&#34;。但是,作为退出之前的最后一步,并将所有内容称为好并准备就绪,git clone 填写您的工作树

它填写工作树的方式git clone一些分支名称,通常为git checkout。此分支名称会记住该分支的最新提交的哈希ID。该提交是从索引进行的,并且该索引中没有master个文件。所以最新的.exe提交没有{{1}其中的文件。

由于此工作树全新,并且正在检出的提交中没有master个文件,因此新的工作树中没有.exe个文件。这就是他们失踪的原因。

如果存储库中某些其他提交中存在<{1}}个文件 ,那么它们就在存储库中,您可以将它们删除。你只是用一个简单的方法来解决它们:

.exe

因为只有 在索引中提取,然后在工作树中提取为.exe上的最新提交保存的文件。

那么在的地方你得到了.exe个文件?

那么,那部分取决于你。 Git在这里没有为您提供预先打包的解决方案。它们可能位于您正在克隆的另一个Git存储库的工作树中,但克隆协议中没有任何内容可以使用其他Git的工作树

处理此问题的一种方法是让提交不包含最新的git checkout master 文件。然后你可以告诉Git:

    提取到我的工作树中,无需提取到索引中,来自提交的所有文件,其哈希ID为master
例如,假设该提交当然具有该哈希ID。事实证明这非常困难,因为Git 真的希望在将文件复制到工作树之前将文件从提交中提取到索引中。将它们放入索引会使它们被跟踪,这不是你想要的。当然,首先将这些.exe文件放入提交中需要 - 好吧,还有什么:等待它......你猜对了吗?是的,这需要将这些.exe文件放入索引中!

Git刚刚赢了,让你双管齐下。要么跟踪文件,所以它们在索引中,所以他们进入提交;或者它们未被跟踪,因此它们不在索引中,因此它们进入提交。选择一个并坚持下去。如果您愿意,可以使用feede3e或此存储库的单独克隆或完全独立的存储库来创建第二个存储库或工作树,该存储库或工作树使用不同的分支 是否跟踪并提交了.exe个文件。实际上,您可能希望此分支或其他存储库仅跟踪和保存 .exe文件。然后,您只需从那里复制git worktree add个文件。

或者,当然,您可以从拥有它们的某个地方获取它们,但是通过.exe以外的某种方法获取它们。

实际上可以在没有单独的工作树的情况下完成所有这些操作,使用各种Git的管道命令和临时索引,但它& #39;相当棘手,而不是Git是如何构建的。无论如何,请注意你需要一个名字 - 比如分支名称 - 你可以很容易地记住这个名字来获得最新的使用最新的 .exe文件进行提交。有一个分支名称可以为您记住哈希ID,提交对象保存文件,还记住以前的提交对象...那就是分支。这就是Git 做的事情:它保留了记住提交哈希的分支名称,这些哈希记住了从索引中保存的文件那么你真的想要一个单独的工作树和单独的索引来更新和提交文件。你真的不希望在Git模型之外工作毕竟。)

.exe文件是红色鲱鱼

git clone中的条目是两个主要内容:

  • 禁止对未跟踪文件的投诉。如果.exe存在于工作树中但不在索引中,因此不会保存在下一个.gitignore中,Git 会骚扰。它一遍又一遍地告诉你,&#34;嘿,.gitignore不会被提交!请记住将foo.exe添加到索引中!不要忘记git commit,否则它不会被提交!&#34;这令人讨厌,并且妨碍了您想要看到的抱怨,关于您真正 忘记的文件。因此,将foo.exefoo.exe添加到foo.exe会关闭此投诉。

  • 它会阻止foo.exe*.exe或类似名称​​自动添加。您可以通过提及目录名称,使用.gitignore或使用{{1}之类的shell globs来一次性地foo.exe将一个文件一次git add -a到索引中,而是添加脏工作树文件。 }}。如果git add当前未跟踪列在--all中,则这些实际上不会将git add *复制到索引中。甚至foo.exe也会跳过它,并提出投诉; .gitignorefoo.exe会跳过它而不会抱怨。

请注意,如果跟踪 文件,则在git add *中列出文件名无效。 git add .中的条目主要是阻止跟踪 跟踪文件,而不是阻止任何已生效的文件。

答案 1 :(得分:0)

您的构建文件位于bin文件夹中。所以你必须加入你的.gitignore:

bin/*.exe or bin/* 

你应该从你的gitignore文件中删除这一行:

**/*.exe

编辑:如果你想忽略除了其中一些文件以外的所有exe文件,你可以使用“!”来排除它们。在行模式的开头,看看这个https://stackoverflow.com/a/987162/5410373