Skip to content

Instantly share code, notes, and snippets.

@tf
Last active March 25, 2026 16:42
Show Gist options
  • Select an option

  • Save tf/fd8e93a83bfa6dc6219a869a66c1e630 to your computer and use it in GitHub Desktop.

Select an option

Save tf/fd8e93a83bfa6dc6219a869a66c1e630 to your computer and use it in GitHub Desktop.
EXPERIMENTAL: jj pin – Guard the tree at a bookmark during history cleanup
# 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