Files
2025-11-30 09:08:16 +08:00

4.0 KiB

Batch Operations on Multiple Revisions

Problem

When you need to update descriptions for multiple revisions (e.g., replacing line number references with labels), bash syntax and piping can be tricky.

Anti-Pattern

# ❌ This will fail with syntax errors
for rev in unxn mktt stnq; do
  jj log -r $rev | sed 's/L123/label/' | jj desc -r $rev --stdin
done

# Issues:
# 1. Missing -n1 --no-graph -T description (gets full log output)
# 2. Unquoted variables ($rev) can break with special chars
# 3. Complex pipes in one-liners are fragile
# ✅ Robust pattern using temporary files
for rev in unxn mktt stnq rwyq roww; do
  # Extract description to file
  jj log -r "$rev" -n1 --no-graph -T description > /tmp/desc_${rev}_old.txt

  # Transform using sed/awk/etc
  sed -f /tmp/replacements.sed /tmp/desc_${rev}_old.txt > /tmp/desc_${rev}_new.txt

  # Apply back to revision
  jj desc -r "$rev" --stdin < /tmp/desc_${rev}_new.txt
done

echo "✅ All descriptions updated"

Benefits:

  • Each step is visible and debuggable
  • Can inspect intermediate files if something goes wrong
  • Easy to retry individual revisions
  • Works with complex transformations

Pattern 2: One Command at a Time

# ✅ Alternative: Sequential approach
jj log -r unxn -n1 --no-graph -T description | \
  sed 's/L123/@label/' > /tmp/desc_unxn.txt
jj desc -r unxn --stdin < /tmp/desc_unxn.txt

jj log -r mktt -n1 --no-graph -T description | \
  sed 's/L123/@label/' > /tmp/desc_mktt.txt
jj desc -r mktt --stdin < /tmp/desc_mktt.txt

# etc.

Benefits:

  • Even more explicit
  • Easy to stop/resume
  • Perfect for copy-paste execution

Pattern 3: Using sed Script File

# Create reusable sed script
cat > /tmp/replacements.sed << 'EOF'
s/L596-617/@types-de-cartes/g
s/L1242-1253/@carte-eglise/g
s/L659-665/@couts-marche/g
EOF

# Apply to all revisions
for rev in unxn mktt stnq; do
  jj log -r "$rev" -n1 --no-graph -T description | \
    sed -f /tmp/replacements.sed | \
    jj desc -r "$rev" --stdin
done

Benefits:

  • Reusable transformation logic
  • Easy to test sed script independently
  • Cleaner loop body

Common Mistakes

1. Missing Template Specification

# ❌ Wrong: gets formatted log output
jj log -r xyz | sed 's/old/new/'

# ✅ Correct: extract just description
jj log -r xyz -n1 --no-graph -T description | sed 's/old/new/'

2. Unquoted Variables

# ❌ Breaks with special characters in rev names
for rev in a b c; do
  jj log -r $rev  # Unquoted
done

# ✅ Always quote
for rev in a b c; do
  jj log -r "$rev"  # Quoted
done

3. Fragile One-Liners

# ❌ Hard to debug, fragile
for rev in a b c; do jj log -r $rev -n1 --no-graph -T description | sed 's/x/y/' | jj desc -r $rev --stdin; done

# ✅ Readable, debuggable
for rev in a b c; do
  jj log -r "$rev" -n1 --no-graph -T description | \
    sed 's/x/y/' > /tmp/desc_${rev}.txt
  jj desc -r "$rev" --stdin < /tmp/desc_${rev}.txt
done

Real-World Example

Replacing all line number references with Typst labels across 10 revisions:

# 1. Create sed replacement script
cat > /tmp/sed_replacements.txt << 'EOF'
s/5F\.typ L596-617/5F.typ @types-de-cartes/g
s/5F\.typ L1242-1253/5F.typ @carte-eglise-en-pierre/g
s/5F\.typ L659-665/5F.typ @couts-marche/g
# ... etc
EOF

# 2. Process each revision
for rev in unxn mktt stnq rwyq roww wltq syun zkru mszz ovrv; do
  jj log -r "$rev" -n1 --no-graph -T description | \
    sed -f /tmp/sed_replacements.txt > "/tmp/desc_${rev}_new.txt"
  jj desc -r "$rev" --stdin < "/tmp/desc_${rev}_new.txt"
done

# 3. Verify one result
jj log -r mktt -n1 --no-graph -T description | head -5

Verification

Always verify the results after batch operations:

# Quick check: first line of each description
for rev in unxn mktt stnq; do
  echo "=== $rev ==="
  jj log -r "$rev" -n1 --no-graph -T description | head -3
done

# Or use jj log with custom template
jj log -r 'unxn | mktt | stnq' -T 'change_id.shortest(4) ++ " " ++ description.first_line() ++ "\n"'