Skip to content

Commit ff4bb42

Browse files
committed
chore: update merge-branches.sh
1 parent b1cfe28 commit ff4bb42

1 file changed

Lines changed: 69 additions & 22 deletions

File tree

‎api/scripts/merge-branches.sh‎

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,30 @@
1818

1919
set -euo pipefail
2020

21+
log() {
22+
echo "==> $*"
23+
}
24+
25+
error() {
26+
echo "==> ERROR: $*" >&2
27+
}
28+
29+
fail() {
30+
error "$@"
31+
exit 1
32+
}
33+
34+
# Catch-all for any command that fails without its own error message.
35+
trap 'error "Command failed (exit $?) at line $LINENO: $BASH_COMMAND"' ERR
36+
2137
remote="${1:-}"
2238

2339
if [[ -z "$remote" ]]; then
2440
read -r -p "Remote (e.g. origin): " remote < /dev/tty
2541
fi
2642

2743
if [[ -z "$remote" ]]; then
44+
error "Remote is required."
2845
echo "Usage: $0 <remote> [branches]" >&2
2946
exit 1
3047
fi
@@ -42,8 +59,7 @@ else
4259
fi
4360

4461
if ! git remote get-url "$remote" > /dev/null 2>&1; then
45-
echo "Error: remote '$remote' does not exist." >&2
46-
exit 1
62+
fail "Remote '$remote' does not exist."
4763
fi
4864

4965
branches=()
@@ -55,66 +71,97 @@ while IFS= read -r line; do
5571
done <<< "$input"
5672

5773
if [[ ${#branches[@]} -lt 2 ]]; then
58-
echo "Error: at least 2 branches are required." >&2
59-
exit 1
74+
fail "At least 2 branches are required, got ${#branches[@]}."
6075
fi
6176

6277
for branch in "${branches[@]}"; do
6378
if ! git rev-parse --verify --quiet "refs/heads/$branch" > /dev/null; then
64-
echo "Error: local branch '$branch' does not exist." >&2
65-
exit 1
79+
fail "Local branch '$branch' does not exist."
6680
fi
6781
done
6882

6983
if [[ -n "$(git status --porcelain --untracked-files=no)" ]]; then
70-
echo "Error: working tree has uncommitted changes. Commit or stash them first." >&2
71-
exit 1
84+
fail "Working tree has uncommitted changes. Commit or stash them first."
7285
fi
7386

7487
start_branch="$(git rev-parse --abbrev-ref HEAD)"
88+
branch_count=${#branches[@]}
89+
merge_count=$((branch_count - 1))
7590

7691
in_merge() {
7792
git rev-parse --verify --quiet MERGE_HEAD > /dev/null
7893
}
7994

80-
for ((i = 1; i < ${#branches[@]}; i++)); do
95+
log "Remote: $remote"
96+
log "Merge order: $(printf '%s -> ' "${branches[@]}" | sed 's/ -> $//')"
97+
98+
for ((i = 1; i < branch_count; i++)); do
8199
source_branch="${branches[i - 1]}"
82100
target_branch="${branches[i]}"
83101

84102
echo
85-
echo "==> Merging '$source_branch' into '$target_branch'"
86-
git checkout --quiet "$target_branch"
103+
log "[$i/$merge_count] Checking out '$target_branch'"
104+
if ! git checkout --quiet "$target_branch"; then
105+
fail "Could not check out '$target_branch'."
106+
fi
87107

108+
if git merge-base --is-ancestor "$source_branch" HEAD; then
109+
log "[$i/$merge_count] '$target_branch' already contains '$source_branch', nothing to merge"
110+
continue
111+
fi
112+
113+
log "[$i/$merge_count] Merging '$source_branch' into '$target_branch'"
88114
if git merge --no-edit "$source_branch"; then
115+
log "[$i/$merge_count] Merged '$source_branch' into '$target_branch'"
89116
continue
90117
fi
91118

92119
if ! in_merge; then
93-
echo "Error: merge of '$source_branch' into '$target_branch' failed." >&2
94-
exit 1
120+
fail "Merge of '$source_branch' into '$target_branch' failed (see git output above). You are on '$target_branch'."
95121
fi
96122

123+
error "Merge conflicts while merging '$source_branch' into '$target_branch':"
124+
git diff --name-only --diff-filter=U | sed 's/^/ /' >&2
97125
while true; do
98126
echo
99-
echo "Merge conflicts in '$target_branch'. Resolve them and commit the merge."
127+
echo "Resolve the conflicts in '$target_branch' and commit the merge."
100128
read -r -p "Press Enter to continue..." < /dev/tty
101129

102130
if in_merge; then
103-
echo "Merge is still in progress (unresolved conflicts or not committed yet)."
131+
error "Merge is still in progress (unresolved conflicts or not committed yet)."
104132
elif ! git merge-base --is-ancestor "$source_branch" HEAD; then
105-
echo "'$source_branch' is not merged into '$target_branch' (was the merge aborted?)."
106-
echo "Run 'git merge $source_branch', resolve and commit, or press Ctrl+C to exit."
133+
error "'$source_branch' is not merged into '$target_branch' (was the merge aborted?)."
134+
echo "Run 'git merge $source_branch', resolve and commit, or press Ctrl+C to exit." >&2
107135
else
136+
log "[$i/$merge_count] Merged '$source_branch' into '$target_branch' (conflicts resolved)"
108137
break
109138
fi
110139
done
111140
done
112141

113-
git checkout --quiet "$start_branch"
114-
115142
echo
116-
echo "==> Pushing to '$remote': ${branches[*]}"
117-
git push "$remote" "${branches[@]}"
143+
log "Switching back to '$start_branch'"
144+
if ! git checkout --quiet "$start_branch"; then
145+
error "Could not switch back to '$start_branch', continuing with push."
146+
fi
147+
148+
failed_pushes=()
149+
for ((i = 0; i < branch_count; i++)); do
150+
branch="${branches[i]}"
151+
152+
echo
153+
log "[$((i + 1))/$branch_count] Pushing '$branch' to '$remote'"
154+
if git push --quiet "$remote" "$branch"; then
155+
log "[$((i + 1))/$branch_count] Pushed '$branch' to '$remote'"
156+
else
157+
error "Failed to push '$branch' to '$remote'."
158+
failed_pushes+=("$branch")
159+
fi
160+
done
118161

119162
echo
120-
echo "==> Done. Merged and pushed: ${branches[*]}"
163+
if [[ ${#failed_pushes[@]} -gt 0 ]]; then
164+
fail "Merged all branches, but failed to push: ${failed_pushes[*]}"
165+
fi
166+
167+
log "Done. Merged and pushed: ${branches[*]}"

0 commit comments

Comments
 (0)