What are commit-ish and tree-ish in Git?
Asked Answered
R

2

148

The Question

What are specific examples of commit-ish and tree-ish in Git?

The Stack Overflow question "What does tree-ish mean in git?" deals with tree-ish specifically, but I want to understand more about both.

Background

Usages in Documentation

The Git documentation makes several references to "commit-ish" and "tree-ish". For example, if you're examining the Git source code:

$ git grep --files-with-matches --extended-regexp "commit(-)*ish"
config.txt
git-describe.txt
git-fast-import.txt
git-name-rev.txt
git-push.txt
git-rebase.txt
git-rev-parse.txt
git.txt
gitcli.txt
glossary-content.txt
howto/revert-branch-rebase.txt
revisions.txt

and

$ git grep --files-with-matches --extended-regexp "tree(-)*ish" | \
$ grep --invert-match RelNotes
diff-format.txt
diff-generate-patch.txt
git-archive.txt
git-cat-file.txt
git-checkout.txt
git-diff-index.txt
git-diff-tree.txt
git-ls-files.txt
git-ls-tree.txt
git-merge-tree.txt
git-read-tree.txt
git-reset.txt
git-svn.txt
git.txt
gitcli.txt
gittutorial-2.txt
glossary-content.txt
revisions.txt

Definitions

The Git documentation defines what "commit-ish" and "tree-ish" are:

<tree>

Indicates a tree object name.

<commit>

Indicates a commit object name.

<tree-ish>

Indicates a tree, commit or tag object name. A command that takes a <tree-ish> argument ultimately wants to operate on a <tree> object but automatically dereferences <commit> and <tag> objects that point at a <tree>.

<commit-ish>

Indicates a commit or tag object name. A command that takes a <commit-ish> argument ultimately wants to operate on a <commit> object but automatically dereferences <tag> objects that point at a <commit>.

The Documentation isn't Clear Enough

Even though the documentation above defines what "commit-ish" and "tree-ish" are, I still find it to be too vague and unclear.

What are specific examples of "commit-ish" and "tree-ish", and how are they different from each other?

Rookery answered 25/4, 2014 at 21:41 Comment(1)
See also the online gitglossary, or use man gitglossary in your CLIIllaudable
R
203

The Short Answer (TL;DR)

Here's a complete list of commit-ish and tree-ish identifiers (from the Git revisions documentation):

----------------------------------------------------------------------
|    Commit-ish/Tree-ish    |                Examples
----------------------------------------------------------------------
|  1. <sha1>                | dae86e1950b1277e545cee180551750029cfe735
|  2. <describeOutput>      | v1.7.4.2-679-g3bee7fb
|  3. <refname>             | master, heads/master, refs/heads/master
|  4. <refname>@{<date>}    | master@{yesterday}, HEAD@{5 minutes ago}
|  5. <refname>@{<n>}       | master@{1}
|  6. @{<n>}                | @{1}
|  7. @{-<n>}               | @{-1}
|  8. <refname>@{upstream}  | master@{upstream}, @{u}
|  9. <rev>^                | HEAD^, v1.5.1^0
| 10. <rev>~<n>             | master~3
| 11. <rev>^{<type>}        | v0.99.8^{commit}
| 12. <rev>^{}              | v0.99.8^{}
| 13. <rev>^{/<text>}       | HEAD^{/fix nasty bug}
| 14. :/<text>              | :/fix nasty bug
----------------------------------------------------------------------
|       Tree-ish only       |                Examples
----------------------------------------------------------------------
| 15. <rev>:<path>          | HEAD:README.txt, master:sub-directory/
----------------------------------------------------------------------
|         Tree-ish?         |                Examples
----------------------------------------------------------------------
| 16. :<n>:<path>           | :0:README, :README
----------------------------------------------------------------------

Identifiers #1-14 are all "commit-ish", because they all lead to commits, but because commits also point to directory trees, they all ultimately lead to (sub)directory tree objects, and can therefore also be used as "tree-ish".

#15 can also be used as tree-ish when it refers to a (sub)directory, but it can also be used to identify specific files. When it refers to files, I'm not sure if it's still considered "tree-ish", or if acts more like "blob-ish" (Git refers to files as "blobs").

The Long Answer

Commits and Directory Trees in Git

At its lowest levels, Git keeps track of source code using four fundamental objects:

  1. Annotated tags, which point to commits.
  2. Commits, which point to the root directory tree of your project.
  3. Trees, which are directories and subdirectories.
  4. Blobs, which are files.

Each of these objects has its own sha1 hash ID, since Linus Torvalds designed Git like an content- addressable filesystem, i.e. files can be retrieved based on their content (sha1 IDs are generated from file content). The Pro Git book gives this example diagram:

Figure 9-3 from Pro Git book

Commit-ish vs Tree-ish

Many Git commands can accept special identifiers for commits and (sub)directory trees:

  • "Commit-ish" are identifiers that ultimately lead to a commit object. For example,

    tag -> commit

  • "Tree-ish" are identifiers that ultimately lead to tree (i.e. directory) objects.

    tag -> commit -> project-root-directory

Because commit objects always point to a directory tree object (the root directory of your project), any identifier that is "commit-ish" is, by definition, also "tree-ish". In other words, any identifier that leads to a commit object can also be used to lead to a (sub)directory tree object.

But since directory tree objects never point to commits in Git's versioning system, not every identifier that points to a (sub)directory tree can also be used to point to a commit. In other words, the set of "commit-ish" identifiers is a strict subset of the set of "tree-ish" identifiers.

The set of tree-ish identifiers that cannot be used as commit-ish are

  1. <rev>:<path>, which leads directly to directory trees, not commit objects. For example, HEAD:subdirectory.

  2. Sha1 identifiers of directory tree objects.

Rookery answered 25/4, 2014 at 21:41 Comment(3)
Dont' forget about stash@{0}. I'd like to know where that fits into all this. Are there any other things like the stash (my-thing@{0})? Is the stash just a <refname>?Metry
It hasn't been made clear explicitly that a tree-ish identifier seems to be a more specific identifier than a commit-ish identifier. Maybe I'm weird but that's the only sensible way to explain it IMOQuentinquercetin
So is <rev> yet another synonym for commit-ish?, or something else entirely?Etch
O
50

Note for non-native English [sic!] speakers: "-ish" is a suffix that can be applied to an adjective in order to indicate "having qualities like" or "slightly" - see http://chambers.co.uk/search/?query=ish&title=21st

Hence "tree-ish" - like a "tree" .... "commit-ish" - like a "commit"

eg "Mars appears like a reddish star" ("d" is doubled !); "the food on the plate was not hot, but warmish"

I believe that this helps explain "what are ..." better, in that it explains the language usage.

Opposition answered 1/12, 2016 at 12:3 Comment(4)
I've always interpreted "tree-ish" and "commit-ish" to be analogous to saying "Swedish" or "English". The usage you describe makes less sense to me because that form of "ish" creates an adjective. But the rev isn't "like" a tree or commit, it is a tree or commit. On the other hand if you think of "ish" as a language suffix then they make more sense as nouns on the command line, where "tree-ish" is the language that forms the noun. I don't know which interpretation was the intent of the authors, but that's how I've always seen it.Coldblooded
I see your point, but I was just giving the impression I have, as a native English speaker !Opposition
I'd tend to agree with @Opposition (albeit I'm natively a French speaker) ; while technically "commit-ish" should be an adjective, I've noticed that terms that you make up but that you often use tend to become nouns. A few months ago I used the term "bus width" often, and eventually I just started writing "buswidth" as a whole word as if it were a noun because of how familiar I became with it. Think of like Linux's termios, or the french expression bon jour ("good day"), that eventually became bonjour. I'm actually surprised they kept writing it commit-ish, and not commitish.Wily
In the sense that adjectives like "tree-ish" and "commit-ish" are used as nouns, it's a form of ellipsis; they really mean "tree-like thing" and "commit-like thing". Perhaps "pseudo-tree" and "pseudo-commit" would've been more obvious terms to non-English speakers, by analogy with "pseudo-code".Wittgenstein

© 2022 - 2024 — McMap. All rights reserved.