Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
registered_at: 2026-02-25T11:53:53Z
change_id: 2602251153-pr-apply-switch-back
baseline: 3ae1eedce4ac7c85de33e2f621ef820b07b4ea79
archived_at: 2026-02-25T12:22:03Z
---

# Change request: conf.sh cmd_apply should switch back to original branch after sending PR

## Why

When `cmd_apply` is called on a PR branch, it needs to switch to the default branch, fast-forward it, and then switch back to the original branch. Currently `cmd_ffdefault` in `pr.sh` switches back to the original branch immediately after fast-forwarding, instead of letting the caller control the return flow.
18 changes: 18 additions & 0 deletions uspecs/changes/archive/2602/2602251222-pr-apply-switch-back/how.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# How: pr.sh cmd_apply should switch back to original branch after sending PR

## Approach

- Fix `cmd_ffdefault` in `pr.sh`: remove the switch-back block and its cleanup trap so the command
stays on the default branch after fast-forwarding. This makes it a clean primitive: switch to
default if needed, fetch, fast-forward, done.

- Fix `cmd_apply` in `conf.sh`: move the `prev_branch` capture to before the `ffdefault` call.
Currently it is captured after `ffdefault` has already switched back, which is redundant and
obscures intent. With `ffdefault` no longer switching back, the correct branch is captured before
any switching occurs, and `pr.sh pr --next-branch "$prev_branch"` (already present) handles the
final switch-back.

References:

- [uspecs/u/scripts/_lib/pr.sh](../../../../u/scripts/_lib/pr.sh)
- [uspecs/u/scripts/conf.sh](../../../../u/scripts/conf.sh)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Implementation plan: conf.sh cmd_apply should switch back to original branch after sending PR

## Construction

- [x] update: [uspecs/u/scripts/_lib/pr.sh](../../../../u/scripts/_lib/pr.sh)
- fix: remove switch-back block (lines 211-215) and its cleanup trap (line 200) from `cmd_ffdefault` so it stays on the default branch after fast-forwarding

- [x] update: [uspecs/u/scripts/conf.sh](../../../../u/scripts/conf.sh)
- fix: move `prev_branch` capture in `cmd_apply` to before the `ffdefault` call so the original branch is remembered before any switching occurs

- [x] update: [uspecs/u/scripts/conf.sh](../../../../u/scripts/conf.sh)
- add: ERR trap in `cmd_apply` after `ffdefault` succeeds to switch back to `prev_branch` on failure; clear trap after `pr.sh pr` succeeds
9 changes: 0 additions & 9 deletions uspecs/u/scripts/_lib/pr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,9 @@ cmd_ffdefault() {
local current_branch
current_branch=$(git symbolic-ref --short HEAD)

local switched=false
if [[ "$current_branch" != "$default_branch" ]]; then
echo "Switching from '$current_branch' to '$default_branch'..."
git checkout "$default_branch"
switched=true
trap 'git merge --abort 2>/dev/null || true; git checkout "$current_branch"' EXIT
fi

echo "Fetching $pr_remote/$default_branch..."
Expand All @@ -207,12 +204,6 @@ cmd_ffdefault() {
if ! git merge --ff-only "$pr_remote/$default_branch" 2>&1; then
error "Cannot fast-forward '$default_branch' to '$pr_remote/$default_branch'. The branches have diverged."
fi

if [[ "$switched" == "true" ]]; then
trap - EXIT
echo "Switching back to '$current_branch'..."
git checkout "$current_branch"
fi
}

cmd_pr() {
Expand Down
10 changes: 6 additions & 4 deletions uspecs/u/scripts/conf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -581,9 +581,12 @@ cmd_apply() {
error "uspecs is already installed, use update instead"
fi

# PR: fast-forward default branch (may update local uspecs.yml)
# PR: remember current branch, then fast-forward default branch (may update local uspecs.yml)
local prev_branch=""
if [[ "$pr_flag" == "true" ]]; then
prev_branch=$(cd "$project_dir" && git symbolic-ref --short HEAD)
(cd "$project_dir" && bash "$script_dir/_lib/pr.sh" ffdefault)
trap 'git -C "$project_dir" checkout "$prev_branch" 2>/dev/null || true' ERR

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The variables $project_dir and $prev_branch are inside single quotes in the trap command. This prevents them from being expanded when the trap is defined. As a result, the trap would attempt to execute a command with literal, unexpanded variable names (e.g., git -C "$project_dir"), which will fail.

To ensure the variables are correctly expanded with their values when the trap is defined, you should use double quotes for the outer string and escape the inner double quotes.

Suggested change
trap 'git -C "$project_dir" checkout "$prev_branch" 2>/dev/null || true' ERR
trap "git -C \"$project_dir\" checkout \"$prev_branch\" 2>/dev/null || true" ERR

fi

local -A config
Expand All @@ -610,11 +613,9 @@ cmd_apply() {
show_operation_plan "$command_name" "$current_version" "$version" "$commit" "$commit_timestamp" "$plan_invocation_methods_str" "$pr_flag" "$project_dir" "$script_dir"
confirm_action "$command_name" || return 0

# PR: capture current branch, then create feature branch
# PR: create feature branch
local branch_name="${command_name}-uspecs-${version_string_branch}"
local prev_branch=""
if [[ "$pr_flag" == "true" ]]; then
prev_branch=$(cd "$project_dir" && git symbolic-ref --short HEAD)
(cd "$project_dir" && bash "$script_dir/_lib/pr.sh" prbranch "$branch_name")
fi

Expand Down Expand Up @@ -664,6 +665,7 @@ cmd_apply() {
# Capture PR info from stderr while showing normal output
(cd "$project_dir" && bash "$script_dir/_lib/pr.sh" pr --title "$pr_title" --body "$pr_body" \
--next-branch "$prev_branch" --delete-branch) 2> "$pr_info_file"
trap - ERR

# Parse PR info from temp file
pr_url=$(_grep '^PR_URL=' "$pr_info_file" | cut -d= -f2-)
Expand Down