Search code examples
gitgit-stashgit-plumbing

Check whether a commit is a stash entry


I need to know in my script whether a given commit is a standard commit or a stash entry. The method should work also for dropped stashes that are not garbage collected yet, so it cannot rely on checking sha of existing stash entries (like git rev-parse stash@{X}).


Solution

  • A stash commit has 2 parents. Say parent1 and parent2. parent1 is also the only parent of parent2. The graph is like this,

    *   9129d71 WIP on master: d2b25fd hello world
    |\
    | * f38c1f8 index on master: d2b25fd hello world
    |/
    * d2b25fd hello world
    

    Update:

    As @jthill points out, with git stash -u which also stashes untracked files, the head has a 3rd parent, parent3. parent3 is a root commit.

    *-.   5ec4337 WIP on (no branch): d2b25fd hello world
    |\ \
    | | * b4b28c3 untracked files on (no branch): d2b25fd hello world
    | * ca727e1 index on (no branch): d2b25fd hello world
    |/
    * d2b25fd hello world
    

    The commit messages of them match certain patterns. The message of the stash entry starts with either WIP on $branch: (by git stash) or On $branch: (by git stash push -m $msg), followed by the short sha1sum and the subject of parent1. The message of parent2 startswith index on $branch:, followed by the short sha1sum and the subject of parent1. The message of parent3 also matches a pattern untracked files on $branch. On a detached HEAD, $branch is literal (no branch).

    We can forge 3 or 4 commits with the same graph and messages on a normal branch, and the head can also be consumed by git stash apply $commit. But it's not common in real logs. So, if the 3 or 4 commits match the graph and their commit messages match these patterns, the head can be considered as a stash entry.