在Git 2.0版本的"git add --update"语法中,":/"(冒号,正斜杠)的含义是什么?

12
我在几个月前升级了Git,自那以后每次尝试使用`git add --update`命令时都会收到以下弃用通知:
``` 警告:从树的子目录中没有路径参数使用 `git add --update(或 -u)` 的行为将在 Git 2.0 中更改,并且不应再使用。要添加整个树的内容,请运行: git add --update :/ (或 git add -u :/) 要将命令限制为当前目录,请运行: git add --update . (或 git add -u .) 根据当前的Git版本,该命令被限制为当前目录。 ```
这个警告本身是完全有道理的,它让我避免了一些重置操作。我已经习惯了输入`.`或者`:/`,但仍然觉得后者非常奇怪,因为它不像我遇到过的任何其他命令行语法。点号`.`很简单:它只意味着“当前目录”,就像在`find .`中一样,但是什么是`:/`呢?我从来没有在别的地方看到过。它是什么意思呢?
我一直认为它是一个表情符号,但当然不是这样的。
4个回答

14

编辑,2019年11月:我替换了这个答案,因为原来的答案大部分是错误的。

git add中的:/语法使用Git称为 pathspec 的东西。 Pathspecs在 gitglossary 中定义。 值得一提的是,在 gitrevisions 语法中,:/具有完全不同的含义,许多其他命令使用该语法,但不适用于git add。 对于这些其他用途,请参见 VonC 的答案

在pathspecs中,冒号字符应该紧跟着各种修饰符的长格式短格式之一。 在修饰符之后,剩下的内容可以是模式,也可以是被视为文件名的简单字符串。

:/使用短格式。 在短格式中,冒号后的每个被识别的字符都具有某些特殊含义。 斜杠字符/表示在工作树的顶层。1

冒号后的任何未识别字符都是剩余的部分。 在这种情况下,整个序列是冒号和斜杠,因此没有剩余内容。 但是,如果您写了:/README,那么这将意味着工作树顶部的README文件

也就是说,假设您在名为sub/的子目录(子文件夹)中,并且它也有一个README文件。 然后:

git add README

添加了 sub/README(因为你在 sub 中),但是:

git add :/README
或:
git add ../README

添加顶层文件。

对于每个短格式表达式,都有一个长格式变体。虽然有一些没有简写的长格式变体。要使用长格式变量,请写一个冒号,然后是一个开放的括号 (,接着是你想要的许多长格式名称,用逗号分隔。用 close parenthesis ) 结束序列。2 例如,可以编写:(top,icase)readme 来表示工作目录顶部的名为 readme、或 ReadMe、或 README、或任何其他疯狂混合大小写的文件。一些命令行解释器可能需要在带括号的表达式周围加上引号:git add ":(top,icase)readme"

在这种特殊情况下,字符串与Git中的.具有相同的含义。因此,:/::(top) 的意思与 :/:.:(top). 相同。这命名了工作树中的每个文件3。在路径规范语法中省略终止的:是可以的,因此 :/ 也表示工作树中的每个文件


1 现在-至少目前为止-只有两个其他特殊字符,!^,它们都表示“排除”。 因此,使用冒号形式,您可以编写 :/:^:!,或将它们与:/!结合使用。

您可以在短格式后面用第二个冒号终止,即如果您想添加名为的文件,则可以编写:/:!。路径规范:/!:! 的意思是不要添加位于树顶上的文件 !;这只有在您指定添加多个顶部文件时才有意义,例如,git add :/!:! :/:. 将添加除顶层文件!之外的所有文件。

2不要在长格式末尾再添加一个冒号。也就是说,:/: 正确,:(top) 正确,但是:(top): 是错误的!这会让我有时候混乱。

3 当然,通常适用于 .gitignore 规则。请记住,任何已跟踪 的文件-现在在索引中的任何文件-永远不会被忽略!


侧边栏:已删除的文件

据我回忆,Git 1.x 和 2.0 在对先前提交中存在的文件,目前被跟踪(即在索引中存在,可使用 git ls-files --stage 命令查看)但出于某种原因现在不在工作树中的文件处理方式上存在区别。

Git 2.0 的行为是,从工作树中删除的文件往往也会从索引中删除。例如,假设我们运行以下命令:

$ git checkout master

执行以下操作,我们将会在工作树中获得一个名为file的文件,该文件是由master分支上最新提交中的同名文件生成的:

git show master:file > file
$ rm file

这样file就依然在索引中,但不再在工作树中。此时运行git status会显示:

On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    file

no changes added to commit (use "git add" and/or "git commit -a")

现在各种形式的git add都将从索引中删除文件file,包括git add :/以及git add file

$ git add :/
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    file

如果您不希望此移除操作被“添加”到索引中,您有多种选项,包括使用--ignore-removal选项:

$ git reset --hard
HEAD is now at 29c2e68 initial
$ git add --ignore-removal :/
$ git status
On branch master
nothing to commit, working tree clean

所以,如果你正在使用:/,但希望跳过更新(即删除)已删除的文件,请使用--ignore-removal。在 Git 2.x 中,默认为“添加删除”。


@Hashim:您在imgur链接中的输出表明,从工作树中删除的文件现在也从索引中删除了,这是我们在这里所期望的。您使用的Git版本是哪个? - torek
我正在使用2.2.1版本。我的观点是,运行git add :/似乎只添加了那些已被修改的文件,而不是Git仓库中的所有文件,这似乎与这个答案所断言的":/表示工作树中的每个文件"相矛盾。 - Hashim Aziz
@Hashim:如果你的工作树中的文件未被修改,因此与已经在索引中的副本匹配,那么你如何确定 Git 是否将其复制到索引中,并将其保持不变,还是 Git 没有将其复制到索引中,并将其保持不变? - torek
我明白了。我想知道的是,是否继续以我现在的方式使用 git add :/ 是不好的实践。我认为因为 git add :/ 查找工作树中的每个文件,所以它也提交和推送所有这些文件。如果不是这种情况,那么就不会发送任何额外的数据,并且不应该有任何问题,因为它只有效地暂存、提交和推送修改后的更改,对吗? - Hashim Aziz
1
你总是提交所有文件。当所有数据匹配时,提交快照会重复使用现有的冻结和压缩文件,因此重新提交相同的文件没有成本。git push不会推送文件;它推送提交(然后根据需要携带文件)。除了运行git add :/git add -u扫描哪些文件需要编写新的压缩图像所需的时间之外,与仅运行几个单独的git add相比,没有真正的优势或劣势。 - torek
显示剩余4条评论

2

2

1
你说得很对,我已经更改了我的回答。不确定这个问题怎么会在过去的五年里被忽略了... - torek

1
“:/”符号在Git 2.8(2016年3月)中演变为“^{/!-<负模式>}”符号,例如“:/!-foo”。请注意保留HTML标签。

请参见commit 0769854 (2016年1月31日)和commit 06b6b68 (2016年1月10日),作者为Will Palmer (wpalmer)
(由Junio C Hamano -- gitster --commit fb79532中合并,2016年2月10日)

现在可以使用:/!-<negative pattern>正则表达式样式来命名提交,因此可以说

$ git rev-parse HEAD^{/!-foo}

它将返回从HEAD可达的第一个提交的哈希值,其提交消息不包含“foo”。 这与现有的^{/

这似乎是文档错误。现在,:/<text> 看起来总是在树对象中搜索名为 <text> 的路径(说实话,这比搜索提交消息要好得多)。 ^{/<text>} 执行以前由 :/<text> 描述的搜索 - 是的,HEAD^{/<text>} 可以匹配 HEAD 本身。HEAD^^{/<text>} 执行文档描述为 HEAD^{/<text>} 的行为。 - Will Palmer
@WillPalmer 这很奇怪:最新版本的文档仍然提到提交信息:https://github.com/git/git/blob/048abe1751e6727bfbacf7b80466d78e04631f94/Documentation/revisions.txt#L185-L197 - VonC
我也发现了这个问题,并向邮件列表发送了一条消息,报告可能存在的错误。 - Will Palmer
@WillPalmer,收到了。 - VonC

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