Last active
February 5, 2026 04:25
-
-
Save zorgiepoo/4615fd7f94cc711f461d7f0c347c5c64 to your computer and use it in GitHub Desktop.
Jujutsu workflow for advancing a bookmark after creating a commit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Add to jj config: | |
| # [aliases] | |
| # cob = ["util", "exec", "--", "jj-commit-onto-bookmark.sh"] | |
| set -euo pipefail | |
| target_bookmark="" | |
| target_bookmark_revset="" | |
| commit_args=() | |
| usage() { | |
| cat <<EOF | |
| Usage: | |
| jj cob (-b|--bookmark BOOKMARK | -r|--revisions BOOKMARK_REVSET [default: @-]) | |
| [-i|--interactive] | |
| [-m|--message MESSAGE] | |
| [FILESETS] | |
| [-- jj commit advanced-args...] | |
| Rebase the working copy commit onto a bookmark with a description and update the bookmark. | |
| This is useful in two scenarios: | |
| 1. Advancing a bookmark from old @- after creating a new commit on top. This is the default behavior of jj cob and behaves like jj commit --advance-branches feature would. | |
| 2. Inserting a commit onto a feature branch when using the megamerge workflow and advancing that bookmark when using -b or -r | |
| By default if no arguments are specified, the bookmark is assumed to be at @-. | |
| Otherwise exactly one of -b/--bookmark or -r/--revisions must be specified. | |
| -i/--interactive and -m/--message are forwarded to 'jj commit' automatically. | |
| Other commit options must be preceded by --. | |
| EOF | |
| exit 1 | |
| } | |
| # Parse options | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| -b|--bookmark) | |
| [[ -n "$target_bookmark_revset" ]] && usage | |
| shift || usage | |
| target_bookmark="$1" | |
| shift | |
| ;; | |
| -r|--revisions) | |
| [[ -n "$target_bookmark" ]] && usage | |
| shift || usage | |
| target_bookmark_revset="$1" | |
| shift | |
| ;; | |
| -i|--interactive) | |
| commit_args+=("$1") | |
| shift | |
| ;; | |
| -m|--message) | |
| commit_args+=("$1") | |
| shift || usage | |
| commit_args+=("$1") | |
| shift | |
| ;; | |
| --) | |
| shift | |
| # Forward everything else verbatim to jj commit | |
| commit_args+=("$@") | |
| break | |
| ;; | |
| -*) | |
| echo "Unknown option: $1" >&2 | |
| usage | |
| ;; | |
| *) | |
| commit_args+=("$@") | |
| break | |
| ;; | |
| esac | |
| done | |
| # Default to @- if neither was specified | |
| if [[ -z "$target_bookmark" && -z "$target_bookmark_revset" ]]; then | |
| target_bookmark_revset="@-" | |
| fi | |
| # Resolve bookmark from revset if needed | |
| if [[ -z "$target_bookmark" ]]; then | |
| bookmarks="$( | |
| jj --ignore-working-copy log \ | |
| --revisions "$target_bookmark_revset" \ | |
| --no-graph \ | |
| --template 'local_bookmarks ++ " "' | |
| )" | |
| read -r -a bookmark_array <<<"$bookmarks" | |
| case "${#bookmark_array[@]}" in | |
| 0) | |
| echo "No local bookmarks found at revision: $target_bookmark_revset" >&2 | |
| exit 1 | |
| ;; | |
| 1) | |
| # Remove trailing * in case it's a local bookmark that has diverged | |
| target_bookmark="${bookmark_array[0]%\*}" | |
| ;; | |
| *) | |
| echo "Multiple local bookmarks found at revision $target_bookmark_revset:" >&2 | |
| for b in "${bookmark_array[@]}"; do | |
| echo " $b" >&2 | |
| done | |
| echo "Please specify one with --bookmark." >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| else | |
| if ! jj --ignore-working-copy log \ | |
| --revisions "$target_bookmark" \ | |
| --no-graph \ | |
| --template 'local_bookmarks ++ " "' \ | |
| >/dev/null 2>&1 | |
| then | |
| echo "Error: bookmark '$target_bookmark' does not exist or is not resolvable." >&2 | |
| exit 1 | |
| fi | |
| fi | |
| jj commit --quiet ${commit_args[@]+"${commit_args[@]}"} | |
| new_change_id="$(jj --ignore-working-copy log --revisions @- --no-graph --template change_id)" | |
| # Rebase will be skipped if it's not necessary | |
| jj --ignore-working-copy rebase --revisions "$new_change_id" --insert-after "$target_bookmark" --quiet | |
| jj --ignore-working-copy bookmark move "$target_bookmark" --to "$new_change_id" --quiet | |
| jj status |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment