What are commit-ish and tree-ish in Git?

Git

Git Problem Overview


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:

> > Indicates a tree object name. > > > Indicates a commit object name. > > > 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>. > > > 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?

Git Solutions


Solution 1 - Git

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.

Solution 2 - Git

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser456814View Question on Stackoverflow
Solution 1 - Gituser456814View Answer on Stackoverflow
Solution 2 - GitMikeWView Answer on Stackoverflow