1

From manpage of git stash:

Testing partial commits

You can use git stash push --keep-index when you want to make two or more commits out of the changes in the work tree, and you want to test each change before committing:

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash push --keep-index    # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part'     # commit fully tested change
$ git stash pop                  # prepare to work on all other changes
# ... repeat above five steps until one commit remains ...
$ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'

How do the commands leave only the first part in working directory, and remove the other parts from the working directory?

git add --patch foo adds foo into the index. (Is foo "the first part"?)

git stash push --keep-index stash everything in the working directory, and roll back only the working directory but not the index

git stash pop will make everything in the stash back to the working directory and the index.

Thanks.

  • "*`git add --patch foo` adds `foo` into the index.*" No, it does not. – melpomene Jan 24 '19 at 22:01
  • Simply put, ```git add --patch``` is the wand and you need to do the magic. It is called interactive staging (https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging) where you can select hunks of code to be included into a commit. Take a look at http://codefoster.com/addpatch/ for specific example workflow with --patch option. Hope this helps! – Mohana Rao Jan 25 '19 at 17:56

1 Answers1

2

As Mohana Rao said, git add --patch doesn't just add the file. It's actually a moderately large Perl script:

$ file $(git --exec-path)/git-add--interactive
/usr/local/libexec/git-core/git-add--interactive: Perl script text executable

and it works by running git diff on the copy of your file that is in the index now, vs the copy of that same file that is in your work-tree now. It presents the diff to you, one diff-hunk at a time. There are a bunch of things you can do, but the simplest is say "insert this one" or "skip this one", and if you pick "add", the Perl script eitr applies the patch, then runs the code underneath git add that copies the actual data, from the patched temporary file. So now the index copy of the file has that one diff-hunk added to it, and if you quit the interactive-add operation, and start again, you won't see the option to add that diff-hunk as it's no longer different.

Once you have the file the way you like it in the index, it's ready—at least in theory—to be committed. Running git commit now would commit what's in the index, not what's in the work-tree. That's fine as far as it goes, but what's in the index has never been tested: it got into the index via the Perl script; it has not been built and run. So now, how will you build and run it?

One way to do that is to git commit it now, extract the commit somewhere else, and run it. That's kind of painful though. But git stash already does that—commits it, that is. In fact, git stash makes two commits, one to hold what's in the index right now, just like a regular git commit would, and another to hold what's in the work-tree right now, just like git commit -a would. Be aware that there's a moderately annoying bug in many version of git stash here. Specifically, they make the right index commit but, depending on what's in the work-tree vs what's in HEAD, can sometimes make the wrong work-tree commit.

Since git stash commits the index, though, and saves the work-tree, it's pretty obvious that Git could then replace the work-tree contents with the committed index contents. Having done that, you can now run your tests. If they pass, you can commit and use git stash pop to put things back.

See also How do I properly git stash/pop in pre-commit hooks to get a clean working tree for tests?

torek
  • 448,244
  • 59
  • 642
  • 775