The aim of this script is to snapshot the current working directory of a git repository to another branch. Afterwards, it switches back to the original branch and restores the original state, including the working directory and staged changes.


function git_snapshot() {
  # Usage: SNAPSHOT=$(git_snapshot <backup_branch> "<commit message>")
  set -e

  # Save the current state.
  BEFORE=$(git rev-parse --abbrev-ref HEAD)
  if [[ "$BEFORE" == 'HEAD' ]]; then
    BEFORE=$(git rev-parse HEAD)
  (>&2 echo "Starting at $BEFORE.")
  git stash push --include-untracked
  (>&2 echo "Stashed changes ($(git rev-parse stash@{0})).")

  # Commit files to other branch.
  git checkout "$1"
  git read-tree -um $BEFORE
  git commit -m "$2"
  (>&2 echo "Saved last commit ($(git rev-parse HEAD)).")
  git stash apply --index stash@{0}
  git add -A
  git commit --amend --no-edit
  (>&2 echo "Amended uncommitted changes ($(git rev-parse HEAD)).")
  SNAPSHOT=$(git rev-parse HEAD)

  # Switch back and restore state.
  git checkout $BEFORE
  git stash apply --index stash@{0}
  (>&2 echo "Restored changes.")

  echo $SNAPSHOT

1 Answer 1


Putting it through shellcheck.net results in quite a lot of cleanups.

Apart from the issues raised there, I'd suggest that at the end of your script, you might want to git stash pop instead of git stash apply when restoring your state.

Inside the function body, you may use local to declare the BEFORE variable. While local is not POSIX compliant, all of GNU and BSD compliant shells support the local keyword.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.