atomic_push.sh 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. #!/usr/bin/env bash
  2. set -e
  3. if [ "$#" -eq 0 ]; then
  4. printf 'Usage: %s <origin> <branch> <branch> ...\n' "$(basename "$0")"
  5. exit 0;
  6. fi
  7. REMOTE="$1"
  8. if ! git ls-remote --exit-code "${REMOTE}" > /dev/null 2>&1; then
  9. echo >&2 "Remote '${REMOTE}' is not valid."
  10. exit 1;
  11. fi
  12. if [ "$#" -lt 3 ]; then
  13. echo >&2 "You must specify at least two branchs to push."
  14. exit 1;
  15. fi
  16. if ! git diff-index --quiet HEAD -- ; then
  17. echo >&2 "Found uncommitted changes in working copy."
  18. exit 1;
  19. fi
  20. ATOMIC_COMMIT_DATE="$(date)"
  21. for BRANCH in "${@:2}"
  22. do
  23. echo "Validating branch '${BRANCH}'..."
  24. # Vailidate that script arguments are valid local branch names
  25. if ! git show-ref --verify --quiet "refs/heads/${BRANCH}"; then
  26. echo >&2 "No such branch named '${BRANCH}'."
  27. exit 1;
  28. fi
  29. # Pull and rebase all branches to ensure we've incorporated any new upstream commits
  30. git checkout --quiet ${BRANCH}
  31. git pull "${REMOTE}" "${BRANCH}" --rebase --quiet
  32. PENDING_COMMITS=$(git log ${REMOTE}/${BRANCH}..HEAD --oneline | grep "^.*$" -c || true)
  33. # Ensure that there is exactly 1 unpushed commit in the branch
  34. if [ "${PENDING_COMMITS}" -ne 1 ]; then
  35. echo >&2 "Expected exactly 1 pending commit for branch '${BRANCH}' but ${PENDING_COMMITS} exist."
  36. exit 1;
  37. fi
  38. # Amend HEAD commit to ensure all branch commit dates are the same
  39. GIT_COMMITTER_DATE="${ATOMIC_COMMIT_DATE}" git commit --amend --no-edit --quiet
  40. done
  41. echo "Pushing to remote '${REMOTE}'..."
  42. git push --atomic "${REMOTE}" "${@:2}"