Hello Johannes,
Thanks for the solution! I think you can avoid conflicts in step 5 by popping off the stash right before step 4a and pushing on the stash right after, like this (the three columns represent the state of the working tree, index, and HEAD):
edit X X X Y Z
git add Y X X X Y Y Z
git commit X X X Y Y Y Z
git stash push (saves X Y +Z) X X X Y Y Y
while test fails {git stash pop (restores X Y +Z) X X X Y Y Y Z
edit X X X Y'Y Y Z
git add Y' X X X Y'Y'Y Z
git commit --amend X X X Y'Y'Y' Z
git stash push (saves X Y' +Z) X X X Y'Y'Y'
}
git stash pop (restores X Y +Z) X X X Y Y Y Z
But the problem with your solution is that you commit before testing and then amend in case of test failure.
The option --keep-index of the command git stash push is supposed to handle this, like specified in the reference documentation: https://git-scm.com/docs/git-stash#Documentation/git-stash.txt-Testingpartialcommits
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'
But --keep-index is fundamentally flawed because though it sets the working tree to the index state (instead of the HEAD state like bare git stash push), it still saves the changes between the HEAD state and the working tree state (i.e. staged changes and unstaged changes). So when you git stash pop, you get conflicts since the working tree is not in the HEAD state like expected, but in the index state.
People have been complaining about this conflict issue on Stack Overflow many times: https://stackoverflow.com/q/7650797/2326961 https://stackoverflow.com/q/20028507/2326961 https://stackoverflow.com/q/49301304/2326961 https://stackoverflow.com/q/25620844/2326961 https://stackoverflow.com/q/20681448/2326961 https://stackoverflow.com/q/57524906/2326961
FEATURE REQUEST So could we add a new option -U|--unstaged (by symmetry with the existing option -S|--staged) to the command git stash push to do what the option --keep-index was trying to achieve? It would: — save the changes between the index state and the working tree state, i.e. only unstaged changes; — set the working tree in the index state.
So the difference with --keep-index is the source: the changes would be computed from the index instead of from HEAD.
With that new option -U|--unstaged, we could solve the ‘testing partial changes before committing’ problem elegantly (called ‘Testing partial commits’ in the reference documentation, which is a bit misleading), that is
— without conflicts contrary to the solution in the reference documentation:
git stash push --keep-index
test
git commit
git stash pop
— without temporary commits contrary to your suggested solution:
git commit
git stash push
test
git commit --amend
git stash pop
— without temporary files contrary to my solution:
git diff >unstaged
git restore .
test
git commit
git apply unstaged
rm unstaged
Like this:
edit X X X Y Z
git add Y X X X Y Y Z
git stash push --unstaged (saves X Y +Z, not X +Y +Z like --keep-index does) X X X Y Y
while test fails {git stash pop (restores X Y +Z) X X X Y Y Z
edit X X X Y'Y Z
git add Y' X X X Y'Y' Z
git stash push --unstaged (saves X Y' +Z) X X X Y'Y'
}
git commit X X X Y Y Y
git stash pop (restores X Y +Z) X X X Y Y Y Z
Best,
Géry Ogam