Last active
March 25, 2026 16:42
-
-
Save tf/fd8e93a83bfa6dc6219a869a66c1e630 to your computer and use it in GitHub Desktop.
EXPERIMENTAL: jj pin – Guard the tree at a bookmark during history cleanup
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
| # jj pin – guard the tree at a bookmark during history cleanup | |
| # Source in .bashrc / .zshrc: source ~/.jj-pin.sh | |
| # | |
| # Pins the closest bookmark to @ by storing a git ref at | |
| # refs/jj-pin/<bookmark> pointing to the bookmark's current commit. | |
| # jj only imports refs/heads, refs/tags, and refs/remotes, so a | |
| # custom ref namespace is invisible to jj and won't affect | |
| # immutable_heads() or jj log. Requires a colocated repo. | |
| # | |
| # Status and diff always compare the pinned commit to the bookmark's | |
| # current commit, regardless of where @ is. | |
| _JJ_PIN_PREFIX=refs/jj-pin | |
| _jj_pin_read() { | |
| local ref | |
| ref=$(git for-each-ref --format='%(refname)' "$_JJ_PIN_PREFIX/" 2>/dev/null | head -1) | |
| [ -n "$ref" ] || return 1 | |
| _jj_pin_bookmark="${ref#"$_JJ_PIN_PREFIX/"}" | |
| _jj_pin_commit=$(git rev-parse "$ref" 2>/dev/null) || return 1 | |
| } | |
| _jj_pin_clear() { | |
| local ref | |
| for ref in $(git for-each-ref --format='%(refname)' "$_JJ_PIN_PREFIX/" 2>/dev/null); do | |
| git update-ref -d "$ref" 2>/dev/null | |
| done | |
| } | |
| jj-pin() { | |
| local bookmark | |
| bookmark=$(jj log -r 'heads(::@ & bookmarks())' --no-graph -T 'local_bookmarks.map(|b| b.name()).join("\n")' 2>/dev/null | head -1) | |
| if [ -z "$bookmark" ]; then | |
| echo "error: no bookmark found at or before @" >&2; return 1 | |
| fi | |
| local commit_id | |
| commit_id=$(jj log -r "$bookmark" --no-graph -T 'commit_id' 2>/dev/null) || { | |
| echo "error: could not resolve bookmark '$bookmark'" >&2; return 1 | |
| } | |
| _jj_pin_clear | |
| git update-ref "$_JJ_PIN_PREFIX/$bookmark" "$commit_id" 2>/dev/null || { | |
| echo "error: could not create ref (colocated git repo required)" >&2; return 1 | |
| } | |
| echo "📌 pinned $bookmark (${commit_id:0:12})" | |
| } | |
| jj-unpin() { | |
| _jj_pin_read || { echo "error: no pin set" >&2; return 1; } | |
| _jj_pin_clear | |
| echo "📌 unpinned $_jj_pin_bookmark" | |
| } | |
| # Short string for prompt integration. | |
| # | |
| # no pin → empty (prints nothing) | |
| # pin set, matches → "📌" | |
| # pin set, changed → "📌✗" | |
| # pin set, error → "📌?" | |
| # | |
| # Usage: PS1='... $(jj-pin-status) $ ' | |
| jj-pin-status() { | |
| _jj_pin_read || return | |
| local pin_tree | |
| pin_tree=$(git rev-parse "${_jj_pin_commit}^{tree}" 2>/dev/null) || { | |
| printf '📌?'; return | |
| } | |
| local current_commit current_tree | |
| current_commit=$(jj log -r "$_jj_pin_bookmark" --no-graph -T 'commit_id' 2>/dev/null) || { | |
| printf '📌?'; return | |
| } | |
| current_tree=$(git rev-parse "${current_commit}^{tree}" 2>/dev/null) || { | |
| printf '📌?'; return | |
| } | |
| if [ "$pin_tree" = "$current_tree" ]; then | |
| printf '📌' | |
| else | |
| printf '📌✗' | |
| fi | |
| } | |
| jj-pin-diff() { | |
| _jj_pin_read || { | |
| echo "error: no pin set (run jj-pin first)" >&2; return 1 | |
| } | |
| local current_commit | |
| current_commit=$(jj log -r "$_jj_pin_bookmark" --no-graph -T 'commit_id' 2>/dev/null) || { | |
| echo "error: could not resolve bookmark '$_jj_pin_bookmark'" >&2; return 1 | |
| } | |
| jj diff --from "$_jj_pin_commit" --to "$current_commit" "$@" | |
| } | |
| # --- Convenience aliases (optional) --- | |
| # alias jp='jj-pin' | |
| # alias jpu='jj-unpin' | |
| # alias jpd='jj-pin-diff' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment