“ git ls-files”的作用是什么?如何从中删除文件?

时间:2019-05-21 09:30:47

标签: git

它显示本地存储库,登台存储库,远程存储库还是其他位置的文件?

我经常看到“ git ls-files”中存在一个文件。该文件已从远程存储库中删除。之后,我尝试进行git pull。但是,该文件仍显示在此命令列表中。它不应在此处显示,因为它也不在远程存储库中。

5 个答案:

答案 0 :(得分:2)

摘要

您需要全神贯注,Git会为每个文件至少存储三个有效副本,有时最多存储五个有效副本:一个在当前提交中, index 中的一个(或两个或三个!),以及工作树中的一个(您可以看到和使用的唯一一个)。 git ls-files命令查看这些副本,然后根据您提供给git ls-files的标志向您介绍其中的一些内容。

如果没有每个文件三到五个副本的想法,那么Git中的许多事情将毫无意义。 (好吧,即使使用,有些事情仍然很棘手,但这完全是另一个问题。)

我认为这里有两个问题。一种需要一些术语,然后另一种应该适用:

  

[git ls-files是否显示本地存储库中的文件,

排序,但:

  

登台存储库

Git没有暂存的存储库。每个存储库都有一个在不同的Git文档中称为 index staging area 的东西。 (有一个过时的名字 cache ,它也出现在the Git glossary中。)

  

远程存储库

绝对不是:根本不需要任何远程存储库(即,其他具有自己的存储库的Git),如果有,只有git fetchgit push的Git可以调用其Git并与他们交换数据。 (好吧,git ls-remote完成了git fetch的头几步,git pull 运行了 git fetch,因此这两个对象也与远程交换数据。但是git ls-files不是。)

  

还是其他地方?

是的,有点。这使我们回到了第一部分。因此,让我们采用the Git glossary中定义的这三个术语。下面的斜体(包括粗斜体)文本直接来自链接的文档:

  • 存储库

    refsobject database的集合,其中包含来自引用的reachable的所有对象,可能还包含一个或多个porcelains的元数据。存储库可以通过alternates mechanism与其他存储库共享一个对象数据库。(所有链接都链接到它们)

    这当然充满了更多的术语。为了尝试揭开它的神秘面纱,他们在这里说的是适当的存储库包括索引和工作树:它主要由 commits < / em>(及其内容)。当然,这要求我们定义“索引”和“工作树”,所以让我们继续:

  • 索引

    具有统计信息的文件的集合,其内容存储为对象。索引是working tree的存储版本。说实话,它还可以包含工作树的第二个甚至第三个版本,这些版本在merging时使用。

  • 工作树 (我通常将此工作树称为):

    实际签出文件的树。工作树通常包含HEAD提交树的内容,以及您已进行但尚未提交的所有本地更改。

商品被永久冻结

当您运行git commit时,Git会为所有文件(无论如何,是所有已跟踪的文件)制作快照,并存储该文件以及一些元数据,例如您的姓名和提交中的电子邮件地址。此提交大部分是永久的-您可以 摆脱提交,通常会遇到很多困难,但是为了方便起见,将它们视为永久的-完全是100%只读的。像这样故意是只读的,因为它允许其他提交 share 相同文件的副本,因此,如果您一次,十次甚至一百万次提交同一文件,则实际上只有存储库中该文件的一个副本。只有在将文件更改为新版本时,Git才必须提交新的单独副本。

对提交进行了编号,但是没有通过简单易用的顺序编号系统进行编号。也就是说,我们可以将它们绘制为一系列简单的带编号或字母的东西:

... <-C4 <-C5 <-C6 ...

其中每个以后的提交都指向其前身。但它们的实际名称是丑陋的哈希ID。每个人都被保证是唯一的,这就是为什么他们必须如此大,丑陋且外观随意。每个哈希ID实际上是根据提交内容计算得出的密码校验和,因此,宇宙中每个地方的每个Git都同意 提交和 only 提交,得到< em>那个校验和。这就是 other 的原因,您甚至Git都无法更改它:如果您从存储库数据库中取出一个提交,则对其进行修改,甚至只更改一次 然后将其放回数据库中,您将得到一个带有新的且不同的哈希ID的 new 提交。

因此,提交将永久冻结。其中的文件也将永久冻结,压缩并以特殊的仅Git格式进行压缩。我喜欢将这些文件称为“冻干”。 this 的意思是,嘿,它们非常适合存档,但是对于完成任何 new 工作……和 来说,它们完全没有用。 em>表示Git 必须提供某种方式来获取这些冻干的文件并将其重新水化为有用的形式。

工作树提供有用形式的副本

事情并没有比这简单得多:工作树具有有用的形式,重新水合的文件副本。由于它们只是计算机上的普通日常文件,因此您可以查看,使用它们,随意更改它们,或者以其他方式使用它们。从技术上讲,它们根本不在存储库中,而是仅位于存储库旁边。在典型设置中,存储库本身位于工作树顶层的.git目录/文件夹中。

很显然,如果您提取了一个提交以使 make 工作树,则每个文件现在必须有两个副本:冻干的提交一个,再加上正常工作的一个。 Git 可以在这里停止。 Mercurial 确实止于此:如果您使用Mercurial而不是Git,则无需担心第三份副本,因为没有第三份副本。但是Git继续存储文件的更多副本。

索引/暂存区位于提交和工作树之间

Git在这里所做的是在冻结干燥的提交副本和工作树副本之间插入每个文件的第三副本。第三份副本采用提交文件格式(即已预先脱水),但是由于未处于 commit 状态,因此实际上并未完全冻结:可以在替换任何时候。这就是git add的工作:git add从工作树中获取文件的普通副本,将其压缩为冻干格式,然后替换所在的副本索引。或者,如果文件根本不在索引中,则会将副本放入索引中。

这就是为什么您必须始终git add归档的原因。在Mercurial中,您仅hg add个文件一次。之后,您只需运行hg commit,Mercurial就会查看它所知道的所有文件,并将其冻结为新的提交。在大型存储库中,这可能需要很长时间。相比之下,Git在索引中已经拥有它应该知道的所有文件,并且已经脱水,因此git commit可以将那些脱水的文件打包为新的冻结提交。这种速度的代价是git add,但是如果您对索引副本进行巧妙的欺骗(例如,使用git add -p),则获得的收益比加速所带来的好处还多。

正如the Git glossary在其索引说明中所述,索引在冲突合并期间承担着扩展角色。当您执行合并操作时(无论是来自git merge还是来自git revertgit cherry-pick或任何其他使用合并引擎的Git命令),并且合并过程都不顺利,Git将每个文件的所有三个输入都放到索引中,这样就得到了三个,而不只是file.ext的一个副本。但是只要您不在合并的中间,索引中就只有一个副本。

通常,索引副本与HEAD冻结副本匹配,或与工作树副本匹配,或两者都匹配。例如,在重新git checkout之后,所有三个副本都匹配。然后,您在工作树中修改file.ext:现在,提交和索引匹配,但是它们与工作树副本不同。然后您git add file.ext,现在索引和工作树匹配了,但是它们与冻结副本不同。然后您git commit进行一次新提交,该提交成为当前提交,并且所有三个副本再次匹配。

请注意,您可以修改工作树副本:

vim file.ext

然后将更新的副本复制到索引中

git add file.ext

然后再次对其进行编辑:

vim file.ext

这样,您可以将所有三个副本制成不同。如果这样做,git status会说您已为提交进行了更改,因为索引副本与当前提交的副本不同,表示您有更改 not 准备提交,因为工作树副本与索引副本不同。

工作树可以包含根本不在索引中的文件

索引最初只是当前提交的副本。然后,Git还将这些文件复制到工作树中,以便您可以使用它们。但是,您可以在工作树中创建文件,并在它们上 not 运行git add。这些文件现在不在索引中,如果您运行git commit,它们也将不在新的提交中,因为Git从索引中构建新的提交。

您还可以索引中删除文件,而无需将其从工作树中删除:

git rm --cached file.ext

删除索引副本。当然,它不能触摸当前的提交冻结副本,但是如果您现在进行一个 new 提交,则新的提交中将根本没有file.ext。 (当然,以前的提交仍然可以。)

现在在您的工作树中 ,并且现在在您的索引 >,是未跟踪的文件。它无法跟踪的原因是它不在您的索引中。将该文件放入索引并进行跟踪,无论您如何将其放入索引。不管您如何从索引中删除它,它都不会被跟踪。因此,这就是索引的最后一个角色:确定已跟踪的文件,因此将在下一次提交中进行。

现在我们可以清楚地看到git ls-files的作用

git ls-files的作用是读取所有内容:提交,索引,工作树。根据您为赋予 git ls-files的参数,它会打印出索引和/或工作树中的某些或所有文件的名称:

git ls-files --stage

列出索引/暂存区域中的文件,以及暂存槽号。 (对于HEAD提交中的副本和工作树,它什么也没说。)或者:

git ls-files --others

列出工作树中但不在索引中的(文件名)。 (它没有对HEAD提交中的副本进行任何说明。)或者:

git ls-files --modified

列出索引中的文件(的名称)与HEAD提交中的文件副本(或不在HEAD提交中的文件副本)完全没有)。没有选项:

git ls-files

列出索引中的文件(名称),而不考虑HEAD提交或工作树中的文件。

答案 1 :(得分:1)

git ls-files在您的情况下可以正常工作。正如您的git status显示X文件已从工作目录中删除一样,这意味着该文件仍存在于索引中。这就是git ls-files之所以显示X的原因,因为该命令显示了索引的内容。

现在,您必须从索引中删除该文件,只需运行:

git rm --cached <pathToXFile>

答案 2 :(得分:1)

只是想分享:

参考已接受的答案 https://stackoverflow.com/a/56242906/2623045 和讨论 https://stackoverflow.com/users/1256452/torek

如果问题是,如果我检查了一个特殊的提交,我如何找出应该在那里的文件/对象,另一个答案可能是这样的:

git ls-tree -r -l HEAD

Torek 还提到“(HEAD 可能是对不存在的分支名称的符号引用)”,但我现在不明白这一点。

更一般:

git ls-tree -r -l commit-hash

这也适用于使用开关 -n(无签出)克隆的存储库

只是想知道输出的神奇之处在哪里

从使用以下命令克隆的存储库中提取: git clone -n​​ https://github.com/nvie/gitflow.git

100755 blob fd16d5168d671b8f9a8a8a6a140d3f7b5dacdccd    git-flow
100644 blob 55198ad82cbfe7249951aa75f1373a476997d33a    git-flow-feature
100644 blob ba485f6fe4b7d9c35bc01d2a6bd4ae201bccc9bd    git-flow-hotfix
100644 blob 5b4e7e807423279d5983c28b16307e40dfdb51d7    git-flow-init
100644 blob cb95bd486deb7089939362705d78b2197893f578    git-flow-release
100644 blob cdbfc717c0f1eb9e653a4d10d7c4df261ed40eab    git-flow-support
100644 blob 8c314996c0ac31f1396c48af5c6511124002dab7    git-flow-version
100644 blob 33274053347f4eec2f27dd8bceca967b89ae02d5    gitflow-common
120000 blob 7b736c183c7f6400b20ea613183d74a55ead78b5    gitflow-shFlags
160000 commit 2fb06af13de884e9680f14a00c82e52a67c867f1  shFlags

我的解释:

散列似乎是“blob 校验和”(没有提交散列)。如果一个提交中有多个文件,则相同的校验和可以出现多次。例如的最后三个半字节100644 看起来像 linux 文件访问属性 (rw-r--r--)。如果对象不是常规文件,则前三个半字节不是 100。在现实生活中 gitflow-shFlags 是一个符号链接,而 shflags 是一个子模块目录。

编辑: 刚刚偶然发现 https://github.com/git/git/blob/master/Documentation/technical/index-format.txt (GOOGLE: git --index-info, STACKOVERFLOW: What does the git index contain EXACTLY?)

32-bit mode, split into (high to low bits)

  4-bit object type
  valid values in binary are 1000 (regular file), 1010 (symbolic link)
  and 1110 (gitlink)

  3-bit unused

  9-bit unix permission. Only 0755 and 0644 are valid for regular files.
  Symbolic links and gitlinks have value 0 in this field.

因此,如果您将半字节解释为八进制值

100644: 1'000' 000'110'100'100 --> 对象类型是普通文件

120000: 1'010' 000'000'000'000 --> 对象类型是符号链接

160000: 1'110' 000'000'000'000 --> 对象类型是 gitlink

OMG:为什么直接从 git 手册页中提取这些信息如此困难?

接下来的问题:什么是“gitlink”?是否只与 git 子模块相关联?

答案 3 :(得分:0)

  

git ls-files将目录缓存索引中的文件列表与   实际的工作目录列表,并显示不同的组合   这两个。

有关信息,请参见here

编辑:

实际目录是您在本地计算机上的当前分支(仅跟踪文件),您可以从现金中删除文件,例如git rm --cached fileName

答案 4 :(得分:0)

  

我经常看到“ git ls-files”中存在一个文件。该文件已从远程存储库中删除。之后,我尝试进行git pull。

您已将该文件添加到索引中,但尚未提交或删除它,因此Git会随身携带该文件,直到您决定如何处理它为止。

如果您不想在索引中将其删除。通常是git rm --cached,或者如果您也想将其从工作树中删除,只需git rm

在工作时经常会发现一些愚蠢的小错误,需要修复,但实际上并不是当前任务的一部分。 Git使处理这样的事情变得非常容易:从维护基础上检出一个bugfix分支,仅提交该修补程序,返回到您正在做的事情,然后合并该修补程序。

Git尽可能做到这一点(而且Git只是默默地做到这一点,这是如此琐碎),Git做到了这一点,而丝毫没有打扰您在飞行中进行的任何其他更改。

您还会发现Git处理飞行工作的方式避免无用的流失的其他情况,重要的是,这就是Git处理飞行工作的方式:它会保留在索引中,直到您决定如何处理它为止。只要您不告诉Git在此处放置其他内容,Git就会默默地添加您添加的内容。