sync-remotes.sh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. # ensure dir
  4. cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
  5. BASE_BRANCHES=( 'release-58' 'release-57' 'release-56' 'release-55' 'master' )
  6. usage() {
  7. cat <<EOF
  8. $0 [option]
  9. options:
  10. -h|--help:
  11. This script works on one of the branches listed in the -b|--base option below.
  12. It tries to merge (by default with --ff-only option)
  13. upstreams branches for the current working branch.
  14. The uppstream branch of the current branch are as below:
  15. * release-55: [] # no upstream for 5.5 opensource edition
  16. * release-56: [] # no upstream for 5.6 opensource edition
  17. * release-57: [] # no upstream for 5.7 opensource edition
  18. * release-58: [] # no upstream for 5.8 opensource edition
  19. * master: [release-5x] # sync release-5x to master
  20. -b|--base:
  21. The base branch of current working branch if currently is not
  22. on one of the following branches.
  23. ${BASE_BRANCHES[@]}
  24. -i|--interactive:
  25. With this option, the script will try to merge upstream
  26. branches to local working branch interactively.
  27. That is, there will be git prompts to edit commit messages etc.
  28. Without this option, the script executes 'git merge' command
  29. with '--ff-only' option which conveniently pulls remote
  30. updates if there is any, and fails when fast-forward is not possible
  31. --dryrun:
  32. Do not perform merge. Run the checks, fetch from remote,
  33. and show what's going to happen.
  34. EOF
  35. }
  36. logerr() {
  37. echo "$(tput setaf 1)ERROR: $1$(tput sgr0)"
  38. }
  39. logwarn() {
  40. echo "$(tput setaf 3)WARNING: $1$(tput sgr0)"
  41. }
  42. logmsg() {
  43. echo "INFO: $1"
  44. }
  45. INTERACTIVE='no'
  46. DRYRUN='no'
  47. while [ "$#" -gt 0 ]; do
  48. case $1 in
  49. -h|--help)
  50. usage
  51. exit 0
  52. ;;
  53. -i|--interactive)
  54. shift
  55. INTERACTIVE='yes'
  56. ;;
  57. -b|--base)
  58. shift
  59. BASE_BRANCH="$1"
  60. shift
  61. ;;
  62. --dryrun)
  63. shift
  64. DRYRUN='yes'
  65. ;;
  66. *)
  67. logerr "Unknown option $1"
  68. exit 1
  69. ;;
  70. esac
  71. done
  72. CURRENT_BRANCH="$(git branch --show-current)"
  73. BASE_BRANCH="${BASE_BRANCH:-${CURRENT_BRANCH}}"
  74. ## check if arg1 is one of the elements in arg2-N
  75. is_element() {
  76. local e match="$1"
  77. shift
  78. for e in "${@}"; do
  79. if [ "$e" = "$match" ]; then
  80. return 0
  81. fi
  82. done
  83. return 1
  84. }
  85. if ! is_element "$BASE_BRANCH" "${BASE_BRANCHES[@]}"; then
  86. logerr "Cannot work with branch $BASE_BRANCH"
  87. logerr "The base branch must be one of: ${BASE_BRANCHES[*]}"
  88. logerr "Change work branch to one of the above."
  89. logerr "OR: use -b|--base to specify from which base branch is current working branch created"
  90. exit 1
  91. fi
  92. ## Find git remotes to fetch from.
  93. ##
  94. ## NOTE: For enterprise, the opensource repo must be added as a remote.
  95. ## Because not all changes in opensource repo are synced to enterprise repo immediately.
  96. ##
  97. ## NOTE: grep -v enterprise here, but why not to match on full repo name 'emqx/emqx.git'?
  98. ## It's because the git remote does not always end with .git
  99. GIT_REMOTE_CE="$(git remote -v | grep 'emqx/emqx' | grep -v enterprise | grep fetch | head -1 | awk '{print $1}' || true)"
  100. if [ -z "$GIT_REMOTE_CE" ]; then
  101. logerr "Cannot find git remote for emqx/emqx"
  102. exit 1
  103. fi
  104. REMOTES=( "${GIT_REMOTE_CE}" )
  105. ## Fetch the remotes
  106. for remote in "${REMOTES[@]}"; do
  107. logwarn "Fetching from remote=${remote} (force tag sync)."
  108. git fetch "$remote" --tags --force
  109. done
  110. logmsg 'Fetched all remotes'
  111. if [ "$INTERACTIVE" = 'yes' ]; then
  112. MERGE_OPTS=''
  113. else
  114. ## Using --ff-only to *check* if the remote is already merged
  115. ## Also conveniently merged it in case it's *not* merged but can be fast-forwarded
  116. ## Alternative is to check with 'git merge-base'
  117. MERGE_OPTS='--ff-only'
  118. fi
  119. ## Get the git remote reference of the given 'release-' or 'main-' branch
  120. remote_ref() {
  121. local branch="$1"
  122. echo -n "${GIT_REMOTE_CE}/${branch} "
  123. }
  124. remote_refs() {
  125. local br
  126. for br in "${@}"; do
  127. remote_ref "$br"
  128. done
  129. }
  130. ## Get upstream branches of the given branch
  131. upstream_branches() {
  132. local base="$1"
  133. case "$base" in
  134. release-55)
  135. remote_ref "$base"
  136. ;;
  137. release-56)
  138. remote_ref "$base"
  139. ;;
  140. release-57)
  141. remote_ref "$base"
  142. ;;
  143. release-58)
  144. remote_ref "$base"
  145. ;;
  146. master)
  147. remote_refs "$base" 'release-55' 'release-56' 'release-57' 'release-58'
  148. ;;
  149. esac
  150. }
  151. for remote_ref in $(upstream_branches "$BASE_BRANCH"); do
  152. if [ "$DRYRUN" = 'yes' ]; then
  153. logmsg "Merge with this command: git merge $MERGE_OPTS $remote_ref"
  154. else
  155. logmsg "Merging $remote_ref"
  156. git merge $MERGE_OPTS "$remote_ref"
  157. fi
  158. done