diff --git a/contributors/emails/willfrombr@Willians-MacBook-Pro.local b/contributors/emails/willfrombr@Willians-MacBook-Pro.local new file mode 100644 index 0000000000..13bffb7446 --- /dev/null +++ b/contributors/emails/willfrombr@Willians-MacBook-Pro.local @@ -0,0 +1 @@ +willfrombr diff --git a/hermes_cli/config_defaults.py b/hermes_cli/config_defaults.py index d47082eb12..2de9540307 100644 --- a/hermes_cli/config_defaults.py +++ b/hermes_cli/config_defaults.py @@ -3265,6 +3265,25 @@ DEFAULT_CONFIG = { # checkout stayed days behind main on a stale branch). Set false to # never auto-switch. "auto_switch_parked_branch": True, + # HOW a clean parked branch with unmerged commits is handled: + # "switch" (default) — switch to the update target; the commits + # stay on the branch (git checkout never + # discards committed work) and a loud notice + # names the branch + count. Deterministic — + # never conflicts — so desktop/gateway/cron + # updates always land on current code. + # "update_in_place" — for a deliberately maintained custom branch + # (local patches on top of main): merge + # origin/ INTO the branch instead. + # The checkout never moves and local commits + # survive; a conflict stops the update + # cleanly with nothing changed. A safety tag + # (pre-update-) is left before the + # merge. `hermes update --switch-branch` + # overrides back to the switch path for one + # run (e.g. a deep feature branch that must + # not accumulate update merge commits). + "parked_branch_strategy": "switch", # Refresh an already-installed cua-driver during `hermes update`. # The refresh is best-effort and macOS-only. Turn this off if the # upstream installer is not appropriate for the machine, for example diff --git a/hermes_cli/subcommands/update.py b/hermes_cli/subcommands/update.py index 71e28166dc..24bfffeb22 100644 --- a/hermes_cli/subcommands/update.py +++ b/hermes_cli/subcommands/update.py @@ -89,14 +89,14 @@ def build_update_parser(subparsers, *, cmd_update: Callable) -> None: action="store_true", default=False, help=( - "When the checkout sits on a branch carrying unmerged commits, " - "switch to the update target and update THERE instead of merging " - "the target into the branch in place. The branch is left exactly " - "as it was — no merge commit is written into its history. Use on " - "long-lived feature branches where an update-driven merge commit " - "would pollute the branch; the default in-place behaviour suits " - "branches that track the target with a small patch set. Still " - "refuses to touch a dirty tree." + "With updates.parked_branch_strategy: update_in_place configured, " + "override it for this run: switch to the update target and update " + "THERE instead of merging the target into the checked-out branch. " + "The branch is left exactly as it was — no merge commit is written " + "into its history. Use on long-lived feature branches where an " + "update-driven merge commit would pollute the branch. No effect " + "under the default strategy (switch), which already switches. " + "Still refuses to touch a dirty tree." ), ) update_parser.add_argument( diff --git a/website/docs/getting-started/updating.md b/website/docs/getting-started/updating.md index 35604ce5eb..5859174c7f 100644 --- a/website/docs/getting-started/updating.md +++ b/website/docs/getting-started/updating.md @@ -49,6 +49,8 @@ If the source checkout was left sitting on a feature branch (by tooling, a workt - **Branch fully merged** (every commit already contained in `origin/main` — `git cherry` reports nothing unmerged): the update says so — `Checkout was parked on '' (fully merged) — switched back to main` — and stays on `main` afterwards. - **Branch has unmerged commits** but the tree is clean: the update still switches to `main` so the update can proceed — this is what non-interactive callers (the desktop update button, gateway `/update`, cron) rely on, since they have no way to resolve a skip. Your commits are untouched: `git checkout` never discards committed work, and the update prints a loud notice naming the branch and commit count, plus the `git checkout ` command to pick the work back up later. +If you *deliberately* run a custom branch (local patches maintained on top of main), set `updates.parked_branch_strategy: update_in_place` in `config.yaml`. The update then merges `origin/main` **into** your branch instead of switching away from it — the checkout never moves, your commits survive, and the running code advances. Fast-forward when possible; on divergence a true merge behind a `pre-update-` safety tag, stopping cleanly (nothing changed) on conflict. `hermes update --switch-branch` overrides back to the switch path for one run — useful on a deep feature branch that must not accumulate update-driven merge commits. + When the parked branch has **uncommitted changes** (dirty tree), Hermes does **not** touch it. The code update is marked **SKIPPED** with a loud warning naming the branch, how far behind `origin/main` it is, and the exact commands to resolve — instead of pretending the update succeeded. The completion line always shows the actual branch and HEAD (`✓ Update complete! [main @ 30fcf9580]`) so drift is visible at a glance. Set `updates.auto_switch_parked_branch: false` in `config.yaml` to disable the auto-switch entirely (the skip warning still fires). ### Local changes on non-interactive updates