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

git

Solution

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:

- Annotated tags, which point to commits.

- Commits, which point to the root directory tree of your project.

- Trees, which are directories and subdirectories.

- 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:

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

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

Sha1 identifiers of directory tree objects.

Problem

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?

Original source

Related problems