What is the meaning of :/ (colon, forward slash) in the 2.0 version of git add --update syntax?

后端 未结 4 515
粉色の甜心
粉色の甜心 2020-12-16 19:02

I upgraded Git a couple months ago and since then I\'ve been receiving the following deprecation notice upon attempting git add --update:

相关标签:
4条回答
  • 2020-12-16 19:31

    The :/ notation evolves in git 2.8 (March 2016) with the '^{/!-<negative pattern>}' notation: :/!-foo

    See commit 0769854 (31 Jan 2016), and commit 06b6b68 (10 Jan 2016) by Will Palmer (wpalmer).
    (Merged by Junio C Hamano -- gitster -- in commit fb79532, 10 Feb 2016)

    To name a commit, you can now use the :/!-<negative pattern> regex style, and consequentially, say

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

    and it will return the hash of the first commit reachable from HEAD, whose commit message does not contain "foo".
    This is the opposite of the existing <rev>^{/<pattern>} syntax.

    The specific use-case this is intended for is to perform an operation, excluding the most-recent commits containing a particular marker.
    For example, if you tend to make "work in progress" commits, with messages beginning with "WIP", you work, then it could be useful to diff against "the most recent commit which was not a WIP commit".
    That sort of thing now possible, via commands such as:

    $ git diff @^{/!-^WIP}
    

    The leader '/!-', rather than simply '/!', to denote a negative match, is chosen to leave room for additional modifiers in the future.

    The new git/revisions doc now states:

    To match messages starting with a string, one can use e.g. ':/^foo'.
    The special sequence ':/!' is reserved for modifiers to what is matched:

    • ':/!-foo' performs a negative match,
    • while ':/!!foo' matches a literal '!' character, followed by 'foo'.
    • Any other sequence beginning with ':/!' is reserved for now.
    0 讨论(0)
  • 2020-12-16 19:36

    The :/ is not the only new syntax, you also have

    :!
    :(exclude)
    

    Making 'git log' ignore changes for certain paths

    So the : signifies that a pathspec is immediately following. Then you have /, also known as the
    root directory, or perhaps in this case representing the root of the repository.

    0 讨论(0)
  • 2020-12-16 19:49

    Edit, Nov 2019: I've replaced this answer as the original was more wrong than right, really.

    The :/ syntax for git add uses what Git calls a pathspec. Pathspecs are defined in the gitglossary. It's worth mentioning that : and :/ have an entirely different meaning in gitrevisions syntax, which is used by many other commands, but not by git add. For these other uses, see VonC's answer.

    In pathspecs, the colon character : is supposed to be followed by either the long form or the short form of various modifiers. After the modifiers, whatever is left over is either a pattern, or a simple string that gets treated as a file name.

    :/ uses the short form. In the short form, each recognized character after the colon has some special meaning. The / character means at the top of the work-tree.1

    Any unrecognized characters after the colon are part of the left-over stuff. In this case, the entire sequence is colon-and-slash, so nothing is left over. However, if you wrote :/README, that would mean the file README in the top of the work-tree.

    That is, suppose you're in the sub-directory (sub-folder) named sub/, and it has a README file as well. Then:

    git add README
    

    adds sub/README (because you're in sub), but:

    git add :/README
    

    or:

    git add ../README
    

    adds the top-level file.

    For each short-form expression, there's a long-form variant. There are long-form variants that do not have short-forms, though. To use the long-form variant, write a colon, then an open parenthesis (, then as many long-form names as you like, separated by commas. End the sequence with a clone parenthesis ).2 For instance, you can write :(top,icase)readme to mean a file named readme, or ReadMe, or README, or any other crazy mixed case, at the top of the work-tree. Some command-line interpreters may require quotes around parenthesized expressions: git add ":(top,icase)readme".

    The empty string, in this particular case, has the same meaning as . to Git. So :/: or :(top) means the same as :/:. or :(top).. This names every file in the work-tree.3 Leaving off the terminating : in the pathspec syntax is OK, so :/ also means every file in the work-tree.


    1There are—at least currently—only two other special characters, ! and ^, which both mean "exclude". So with the colon form, you can write :/ or :^ or :!, or combine them with :/!.

    You can terminate the short form with a second colon, i.e., you can write :/:! if you want to add the file named ! that is at the top of the work-tree. The pathspec :/!:! means do not add the file ! that is at the top of the tree; this would only be meaningful if you said to add multiple top-of-tree files, e.g., git add :/!:! :/:. would add all files except the top-level file !.

    2Do not add another colon at the end of the long form. That is, :/: is correct, and :(top) is correct, but :(top): is wrong! This trips me up now and then.

    3The usual .gitignore rules apply, of course. Remember that any tracked file—any file that is in the index right now—is never ignored!


    Sidebar: removed files

    As I recall, Git 1.x and 2.0 differ in treatment of files that were in the previous commit, are currently tracked (i.e., are present in the index, visible with git ls-files --stage for instance), but—for whatever reason—are not in the work-tree right now.

    The behavior in Git 2.0 is that files removed from the work-tree tend to get removed from the index. For instance, suppose we run:

    $ git checkout master
    

    and get a file named file in the work-tree as a result of the tip commit of master containing the file named file. Then we do:

    $ rm file
    

    so that file is still in the index but is no longer in the work-tree. A git status at this point will say:

    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")
    

    Various forms of git add will now remove the file file from the index. That includes git add :/ as well as git add file:

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

    If you don't want this removal "added" to the index, you have a number of options, including the --ignore-removal option:

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

    So if you are using :/ but want to skip updating (i.e., removing) removed files, use --ignore-removal. The default in Git 2.x is to "add the removal" as well.

    0 讨论(0)
  • 2020-12-16 19:52

    The first answer is not completely correct. In the context of git-add, the :/ cannot be a revision. It is a pathspec. See my answer to the related question "What does "git add -A :/" do?".

    pathspec is defined in gitglossary(7).

    0 讨论(0)
提交回复
热议问题