16

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
jub0bs
  • 60,866
  • 25
  • 183
  • 186
clockworks
  • 3,755
  • 5
  • 37
  • 46

2 Answers2

14

"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.

Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • 2
    One valuable use of the stash is to hold work-in-progress for just a moment while you rebase/merge upstream changes -- since git doesn't let you do a rebase while you have outstanding changes. – Brent Bradburn Mar 04 '16 at 20:54
  • Sometimes you come back later and wish you could up-vote your own post. '+1' for `git commit -a -m "WIP"` as a much better replacement for `git stash`. – Brent Bradburn Jun 22 '16 at 19:43
  • `git stash` can be useful during a rebase -- in case you want to backtrack a bit for evaluating and testing and earlier rebase commit. I don't know if there is an alternative way to replicate what `git stash` does in this scenario. – Brent Bradburn Jul 29 '18 at 01:35
  • what do you mean by _after checking out the "stash" commit_ ? – rvcristiand Jul 31 '20 at 15:25
  • @rvcristiand: I put "stash" in quotes here because it is referring to my _simulated_ stash (with the commit message "stash") -- not referring to the actual "git stash", which I was avoiding. You can check out a specific commit -- The best way is usually to check out a branch that points to it. The point is that `git stash` is a convenience tool that can easily be simulated using the normal commit/checkout mechanisms (which are probably safer). – Brent Bradburn Jul 31 '20 at 17:20
12

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.

jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 1
    Thanks for reply, I made improvements on the question as you offer. Do you have any further explanation why state of the index needs to be recorded. State of the working tree is changed after stash and to be able to restore it we need to keep it, its ok. but is index also changed ? Also, stash can be popped after a week and several commits. Does it really matter restore the index ? – clockworks Sep 24 '14 at 18:21
  • You need to record a distinct object for the index, because the state of the index does not necessarily correspond to the state of the working tree. For instance, you could make local modifications to a file, stage those changes (add them to the index), the make some more modifications, but without staging them; the working tree and the index would then be different. As for why you would want to save the state of the index (as well as that of the working tree)... perhaps staging files for the next commit is a very meticulous and tedious task, and you don't want to have to start from scratch. – jub0bs Sep 24 '14 at 18:24
  • for instance, If Two lines are added to file A and changes added to index. Afterwards two more lines added to the same file. Can we say that half of the changes stored in working tree and the other half is index. So, in order to restore the file after stash, both index and working copy is to be stored. – clockworks Sep 24 '14 at 18:59
  • @stackr That's the idea, yes. – jub0bs Sep 24 '14 at 19:00