Check if Git has changes programmatically
bash, git
Solution
`git stash` is actually a shell (plain sh, not bash) script, so you can look at what it does to decide whether to make a stash:
no_changes () {
git diff-index --quiet --cached HEAD --ignore-submodules -- &&
git diff-files --quiet --ignore-submodules &&
(test -z "$untracked" || test -z "$(untracked_files)")
}
untracked_files () {
excl_opt=--exclude-standard
test "$untracked" = "all" && excl_opt=
git ls-files -o -z $excl_opt
}
You can therefore repeat these tests to see if `git stash` will do anything—but that's actually not the best option:
- If `git stash` will do something, first it repeats these tests (and they say there is something to stash), which makes them happen twice in that case.
- If the "right" set of tests ever change, you can mis-predict `git stash`'s action and get into trouble.
Clearly, what you want is to:
- Run `git stash`, and keep track of whether this did anything.
- Run `git checkout` on the target branch.
- If `git stash` stashed something, run `git stash pop` (or perhaps `--apply --keep-index` first, to see if that will do the trick, and resort to applying without `--keep-index` only if required, etc.).
The tricky part is that first step. It turns out to be easy, you just need to know how `git stash` works in, um, extensive detail, plus some other bits about git's "plumbing commands". You simply grab the previous stash stack top if any before the `git stash save` step, and then grab the new top if any, and compare:
old_stash=$(git rev-parse -q --verify refs/stash)
git stash save [additional arguments here if desired, e.g., -q]
new_stash=$(git rev-parse -q --verify refs/stash)
If the two refs name different commits, or the old ref is empty and the new is not empty, then `git stash` pushed a new stash on the stack. If the two refs are both empty, or the two refs name the same commit, then `git stash` did nothing:
if [ "$old_stash" = "$new_stash" ]; then ...; else ...; fi
or, in your case, perhaps something more like:
[ "$old_stash" != "$new_stash" ] && git stash pop
(these tests make use of the fact that the two empty strings are equal to each other, and not-equal to any non-empty string, in terms of the result from `/bin/[` and the shell's built-in copy thereof).
Problem
I want to write a script that allows me to easily change branches keeping my current changes. ``` git stash go checkout main git stash pop ``` The problem is if there are currently no changes in the repository. Then `stash pop` will pop off a previous stash. What is the easiest way to check if there are changes to pop?