'What are those 'WIP' and 'index' commits that appear after stashing?

When I run git lg on my local development branch, the latest commit is shown as below:

* 7d21213 - (1 hours ago) update business rules - developer1 (HEAD, origin/develop, origin/HEAD, develop)

However, if I stash local changes by running git stash and then run git lg, I get the following:

*  at12334 - (13 seconds ago) WIP on develop: 7d21213 update business rules - developer1 (refs/stash)
|\
| * ef9a11b - (14 seconds ago) index on develop: 7d21213 update business rules - developer1
|/
* 7d21213 - (1 hours ago) update business rules - developer1 (HEAD, origin/develop, origin/HEAD, develop)

What does this mean? It seems that two new commits (labelled index and WIP) are created after stashing. Is that the case, and, if so, what is the logic behind such commits?


Note

git lg

is an alias already defined in the test environment as

git log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)' --all


Solution 1:[1]

git lg? What git lg?

Be aware that lg is not a native Git verb. True, many people use an alias called lg that usually corresponds to

git log --all --oneline --graph --decorate

This definition seems to be the one you're using, here. However, aliases are local; what git lg means in your config may be different to what it means in Bob and Alice's configs.

Therefore, you should always include the definition of a relevant alias in your question, so we (Stack Overflow users) can be on the same page as you, and know exactly what happens when you run

git <alias>

(git lg, here).

What the mysterious objects are

This is explained in the Discussion section of the git-stash man page:

A stash is represented as a commit whose tree records the state of the working directory, and its first parent is the commit at HEAD when the stash was created. The tree of the second parent records the state of the index when the stash is made, and it is made a child of the HEAD commit. The ancestry graph looks like this:

       .----W
      /    /
-----H----I

where H is the HEAD commit, I is a commit that records the state of the index, and W is a commit that records the state of the working tree.

In your case,

  • the object whose short SHA is ef9a11b corresponds to the state of your index (I on the graph above),
  • the object whose short SHA is at12334 corresponds to the state of your working directory (W on the graph above).

Those two objects (W and I) don't normally get listed in the output of git log, but they do if you use the --all flag.

Solution 2:[2]

"WIP" is an acronym for Work-In-Progress. It is meant to suggest that you are temporarily saving the current state of your work even though you aren't at a natural stopping point.

Stashing saves your work in the repository using familiar commit/merge mechanisms. In particular, it is possible to view all currently stashed items in context by running gitk --reflog, although only the most recent stash will be labeled with stash. An important difference between a regular commit and a stash is that when stashes are removed (for example via git stash clear), they are no longer visible in the reflog and will therefore be more difficult to recover.

A stash is normally performed in two parts:

  1. An "index" commit is performed for anything that has been "add"ed since the last commit.
  2. The "WIP" commit is performed as a merge between the working state and the index commit.

If you haven't performed any add operations since the last commit, the index commit will be empty. However, even if the index is empty, it is still committed. The subsequent implicit merge can complicate things if you, for example, wanted to cherry-pick from a stash in order to avoid certain complications associated with git stash pop.


Git's stash mechanism is clever, powerful, and useful, but it is also complicated, error prone, and dangerous. My practice lately has been to avoid the use of git stash in favor of getting similar results with something like git commit -a -m "stash" to save my work and git reset HEAD~1 (after checking out the "stash" commit) to restore it.

This leaves the most useful application of git stash as just being a quick way to get rid of all local changes if you know that you no longer need them.

By the way, you can remove the "WIP" and "index" commits from your logs by running git stash clear -- but don't do that if you have valuable work saved only on the stash.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2