tl;dr
I want to run tests only with staged files before commit:
git stash save -k -u
to stash unstaged/untracked files/changes before testing- run tests with staged files
git stash pop
to restore changes/files at step 1.
The problem is using git stash pop
will raise conflicts on the files with partial staged. Resolving the conflicts will lead to lose the partial staged/unstaged changes (you need to pick partial lines to staged again).
Update: If you want to know the shell script to run this procedure, please jump to the last section for more information.
NOTE: only adjacent lines (or close enough) with partial staged will cause this issue. For example, if you have 6 new line changes in a file:
1 +| a (add to staged)
2 +| b (add to staged)
3 +| c (add to staged)
4 | d (keep unstaged)
5 | e (keep unstaged)
6 | f (keep unstaged)
Now use git stash -k -u
and then git stash pop
will raise conflict.
Demonstrate the question
Git provides three phases for changes before commit: staged
, unstaged
and untracked
.
Any changes will be added to unstaged
. Before commit, you can pick some of lines or files and add them to staged
by git add
.
Now, after adding some of code to staged
, I want to run tests with only staged files to make sure they were suitable for commit, so I need to stash unstaged
and untracked
changes (new files) by git stash -k -u
and keep staged
changes.
Say, for example, I have 3 file changes: file A is fully staged, file B is partial staged (some of code), and file C is a new file which is untracked.
[staged]
file A
file B (only stage some of code)
[unstaged]
file B
[untracked]
file C (new file)
After running git stash -k -u
, all unstaged/untracked changes are stashed.
[staged]
file A
file B (only stage some of code)
[unstaged/untracked]
<none, clean>
Here comes the problem. After running tests and then git stash pop
, it raises conflicts on file B because it is partial staged. I'm sure that I did not change file B when stashing and testing.
I wonder how to auto-merge with git stash pop
without any conflict just like before I stashed them.
My workflow
I think this is a very usual workflow
development start
|
[make changes (unstaged)]
|
(pick changes to staged for commit by `git add`)<---|
| |
V (pick other changes to fulfill tests)
[partial staged/unstaged] |
| |
(stash unstaged changes by `git stash -k -u`) |
| |
(run tests only with staged files for commit) |
| |
(restore stashed files by `git stash pop`) |
| |
|------------<if test failed>-------------|
|
<if test success>
|
[commit staged files by `git commit`]
|
V
keep development or next commit
I need a way to stash pop
without losing staged/unstaged state for all changes. Keeping staged files is very important to commit or fulfill test by adding other changes.
Update with solution: a shell script to run the procedure
According to @torek's answer, I write a shell script to run tests with only staged files:
#!/bin/sh -e
# stash all unstaged changes
# (-k: unstaged files; -u: new added files; -q: quite)
echo '--------------------------------------------------------------'
echo '---- Stash all unstaged/untracked files (git stash -k -u) ----'
echo '--------------------------------------------------------------'
BEFORE_STASH_HASH=$(git rev-parse refs/stash)
git stash -k -u -q
AFTER_STASH_HASH=$(git rev-parse refs/stash)
if [ "$BEFORE_STASH_HASH" == "$AFTER_STASH_HASH" ]; then
echo '\n\n---- Stash failed! Please check and retry. ----\n\n';
exit 1;
fi;
# run test only with staged files
echo '-------------------'
echo '---- Run tests ----'
echo '-------------------'
<run your tests here> || #### <=== replace your test command here
(echo '\n\n---- Tests failed! Please fix it before commit. ----\n\n')
# restore all stashed changes
# http://stackoverflow.com/questions/41304610/
echo '-----------------------------------------------------------'
echo '---- Restore all stashed files (git stash pop --index) ----'
echo '-----------------------------------------------------------'
git reset --hard -q &&
git clean -df -q &&
git stash pop --index -q ||
(echo '\n\n---- Restore failed! Please check and fix it. ----\n\n')