jj-history-investigation

安装量: 47
排名: #15710

安装

npx skills add https://github.com/edmundmiller/dotfiles --skill jj-history-investigation
Jujutsu (jj) History Investigation and Manipulation
Overview
When working with complex jj repositories, you may need to investigate historical commits, split monolithic changes into focused commits, or clean up messy history. This skill documents efficient techniques for:
Investigating commit history
Finding when changes were made and why
Using jj annotate
Tracking down who/when specific lines were added
Splitting commits
Breaking large commits into focused, reviewable pieces
Handling immutability
Overriding protections when rewriting shared history
Cleaning up redundancy
Removing duplicate or empty commits
Resolving conflicts
Fixing merge conflicts after rebases Core Commands Command Purpose Example jj log View commit history jj log -r 'ancestors(@, 10)' jj show Display commit details jj show abc123 jj file annotate Line-by-line change tracking jj file annotate src/main.tex jj edit Start editing a commit jj edit abc123 --ignore-immutable jj split Split a commit into pieces jj split --ignore-immutable path/to/file jj abandon Remove commits from history jj abandon abc123 jj rebase Move commits to new base jj rebase -b main -d new-base Investigation Techniques 1. Finding When a Change Was Made When you know a file changed but not when, use these approaches: Check recent commit messages:

Search for commits mentioning "copyright"

jj log -r 'description(copyright)' --no-graph

Output:

trsozpwy feat(frontmatter): Add post-defense required sections

(shows commits with "copyright" in the message)

View commit details:

Show full commit with statistics

jj show trsozpwy --stat

Show just the files changed

jj show trsozpwy --summary Check specific file history:

See who/when each line was added

jj file annotate src/main.tex | grep "copyrightpage"

Output:

trsozpwy edmund.m 2025-11-09 00:13:05 49: \copyrightpage{2025}

  1. Understanding Commit Lineage Check what's built on top of a commit:

View descendants of commit abc123

jj log -r 'abc123::@' --limit 20

Check ancestors of current commit

jj log -r 'ancestors(@, 10)' Find relationships between branches:

See where main and feature branches diverged

jj log -r 'ancestors(main) & ancestors(feature)'

Check if commit is ancestor of main

jj log -r 'abc123::main' 3. Extracting Specific Commit Information Get commit metadata:

Show commit ID, author, date

jj show abc123 | head -10

Get just the change ID

jj log -r abc123 --no-graph -T 'change_id' Check file changes:

See what changed in a commit

jj diff -r abc123

See specific file diff

jj
diff
-r
abc123 src/main.tex
Splitting Commits
When to Split
Split a commit when it contains multiple logical changes that should be reviewed separately:
Good candidates
"Add frontend + backend + tests + docs"
Mixed concerns
Copyright page + acknowledgments + CV in one commit
Already focused
"Fix typo in README" Basic Split Workflow 1. Check if commit is immutable: jj edit abc123

If error: "Commit abc123 is immutable"

Then use --ignore-immutable flag

  1. Edit the commit: jj edit abc123 --ignore-immutable

Working copy now at abc123

File system shows state at that commit

  1. Split by file/directory:

Split out specific files

jj split --ignore-immutable src/main.tex

jj will prompt for commit messages for:

- Selected changes (what you specified)

- Remaining changes (everything else)

  1. Split incrementally:

After first split, you're at "remaining changes"

Split again to extract more pieces

jj split --ignore-immutable src/chapters/appendix.tex 5. Update commit messages:

Update the commit you just split

jj describe @- -m "feat(frontmatter): Enable copyright page"

Continue until all pieces are separated

Advanced Split Techniques Split and update TODO in same commit:

1. Split out the main change

jj split --ignore-immutable src/main.tex

2. In the split commit, also update TODO.org

Edit TODO.org to mark item as DONE

jj describe -m "feat(frontmatter): Enable copyright page Enable copyright on page ii as recommended by UTD. Mark as complete in TODO.org." Split multiple files into one commit:

Save final state

cp src/main.tex /tmp/main.tex.final

Restore to parent

jj restore --from @- src/main.tex

Apply changes incrementally

Make change 1, commit

Make change 2, commit

etc.

Handling Immutability Why Commits Become Immutable Commits are immutable when: They have descendants (other commits built on top) They're in shared history (pushed to remote) They're marked explicitly in config Overriding Immutability When it's safe: ✅ Local-only history (not pushed) ✅ You own all descendant commits ✅ No collaborators affected How to override:

Edit immutable commit

jj edit abc123 --ignore-immutable

Split immutable commit

jj split --ignore-immutable src/main.tex

Note: This will rewrite ALL descendant commits

What happens:

Before split:

abc123 (monolithic commit)

def456 (descendant 1)

ghi789 (descendant 2)

After split:

abc123 (piece 1)

xyz111 (piece 2)

def456' (rewritten descendant 1)

ghi789' (rewritten descendant 2)

Cleaning Up History Identifying Redundant Commits Find empty commits:

Show commit stats

jj show abc123 --stat

If output shows "0 files changed", it's empty

Find conflicting commits:

Check for conflicts

jj log -r 'all()' | grep conflict

Output:

× abc123 (conflict) feat: Add something

Abandoning Commits Remove redundant commits:

Abandon single commit

jj abandon abc123

Abandon multiple commits

jj abandon abc123 def456 ghi789

What happens:

- Commit is removed from history

- Descendants are rebased onto parent

- Changes are preserved in descendants

Abandon empty commits automatically:

After rebasing, jj may create empty commits

Abandon them to clean up

jj log -r 'all()' --summary | grep "(empty)" jj abandon empty-commit-id Cleaning Up After Split Common pattern:

1. Split monolithic commit

jj edit old-commit --ignore-immutable jj split src/file1.txt jj split src/file2.txt

(repeat for each logical piece)

2. Check for redundant descendants

jj log -r 'old-commit::@' --limit 30

3. Abandon redundant commits

jj abandon redundant-commit-1 redundant-commit-2

4. Verify history

jj log -r 'old-commit::@' --no-graph Resolving Conflicts After Rebase/Split 1. Identify conflicts: jj status

Output:

Warning: There are unresolved conflicts at these paths:

TODO.org 2-sided conflict

  1. Create commit to resolve:

Create new commit on top of conflict

jj new conflicted-commit-id 3. Read conflict markers: cat TODO.org

Output:

<<<<<<< Conflict 1 of 1

+++++++ Contents of side #1

** DONE Add something

%%%%%%% Changes from base to side #2

** TODO Add something

>>>>>>> Conflict 1 of 1 ends

  1. Choose resolution:

Edit file to pick side #1, side #2, or merge both

Remove conflict markers

Or use editor with conflict resolution

jj resolve TODO.org 5. Squash resolution:

Merge resolution into parent

jj squash

This resolves the conflict in the parent commit

Verifying History After Major Changes 1. Check commit lineage:

View commits from base to current

jj log -r 'base-commit::@' --limit 50

Check all commits are present

jj log -r 'commit1 | commit2 | commit3' --no-graph 2. Verify each commit is focused:

For each commit in your split:

jj show commit-id --stat

Should show:

- Small number of files changed

- Logical grouping of changes

- Clear commit message

  1. Check for conflicts:

List all commits with conflicts

jj log -r 'all()' | grep conflict

Should be empty after cleanup

  1. Verify bookmarks:

Check where main/feature branches point

jj log -r 'bookmarks()'

Ensure they're at correct positions

History Health Checklist After split/rebase/cleanup: No conflict markers in jj status No (conflict) labels in jj log No empty (empty) commits (unless intentional) Commit messages are clear and descriptive Each commit has focused changes Bookmarks (main, feature, etc.) point correctly TODO.org or similar files are consistent Real-World Example Scenario: Historical commit trsozpwy contains 6 different changes mixed together. Need to split for review. Investigation phase:

1. Find the commit

jj log -r 'description(post-defense)' --no-graph

Found: trsozpwy

2. Check what's in it

jj show trsozpwy --stat

Shows: 10 files changed

3. Check if immutable

jj edit trsozpwy

Error: Commit is immutable (16 descendants)

4. Verify we can override

jj log -r 'trsozpwy::@' --limit 20

Shows descendant commits, all owned by us

Split phase:

1. Override immutability

jj edit trsozpwy --ignore-immutable

2. Split out Python scripts

jj split --ignore-immutable src/figures/modules/ jj describe @- -m "feat(ch3): Add core overlap Venn diagram scripts"

3. Split out appendix fix

jj split --ignore-immutable src/chapters/appendix-*.tex jj describe @- -m "fix(appendix): Remove 'A' label from solo appendix"

4. Split frontmatter pieces incrementally

(Copyright page)

Edit src/main.tex to add only copyright

jj commit -m "feat(frontmatter): Enable copyright page (2025)"

(Acknowledgments)

Edit src/main.tex to add acknowledgments

jj commit -m "feat(frontmatter): Add acknowledgments section"

(And so on for biographical sketch, CV)

Cleanup phase:

1. Check for redundant descendants

jj log -r 'trsozpwy::@' | grep "Mark post-defense"

Found: kqkm (redundant - duplicates our split work)

2. Abandon redundant commits

jj abandon kqkm lkto qqkq srls

3. Rebase main branch onto splits

jj rebase -b main -d last-split-commit

4. Resolve conflicts

jj new conflicted-commit

Edit TODO.org to pick correct side

jj squash Verification phase:

1. Check final structure

jj log -r 'first-split::@' --limit 30

2. Verify each split commit

jj show trso --stat

Core overlap scripts

jj show nlnr --stat

Appendix fix

jj show zspm --stat

Copyright page

jj show mrpk --stat

Acknowledgments

jj show wqrn --stat

Biographical sketch

jj show ynom --stat

CV

3. Confirm no conflicts

jj status

(should be clean)

4. Check bookmarks

jj log -r 'bookmarks()'

main and Cleanup should be on correct commits

Result: Successfully split 1 monolithic commit into 6 focused commits, each with clear intent and proper TODO.org updates. Tips and Tricks Speed Up Investigation Use aliases for common queries:

In ~/.jjconfig.toml

[ aliases ] recent = [ "log" , "-r" , "ancestors(@, 20)" , "--no-graph" ] conflicts = [ "log" , "-r" , "conflicts()" ] empty = [ "log" , "-r" , "empty()" ] Search commit messages efficiently:

Case-insensitive search

jj log -r 'description("(?i)copyright")'

Multiple terms

jj log
-r
'description(frontmatter) & description(copyright)'
Avoid Common Pitfalls
Don't split without investigation
Always
jj show
first to understand what's in a commit
Save state before split
:
cp important-file /tmp/
before major history rewrites
Split incrementally
Don't try to split everything at once; do one logical piece at a time
Update TODO immediately
Mark TODO items in the same commit that does the work
Verify after each step
Check jj log frequently during split/rebase operations When NOT to Split Commit is already pushed and shared with others Changes are truly atomic (e.g., "Fix typo + its test") Split would make history harder to understand Commit is ancient and rarely viewed References jj Documentation jj Revset Language jj Conflict Resolution
返回排行榜