Skip to content

Commit 4c3d72c

Browse files
committed
chore: add jj skill
1 parent 8219e45 commit 4c3d72c

File tree

1 file changed

+294
-0
lines changed

1 file changed

+294
-0
lines changed

.opencode/skill/jj-vcs/SKILL.md

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
---
2+
name: jj-vcs
3+
description: Guides agents through using the Jujutsu (jj) version control system. Activate when the user mentions jj, jujutsu, or when working in a repository with a .jj directory. Teaches proper workflow for atomic commits and change management.
4+
---
5+
6+
# Jujutsu (jj) Version Control System
7+
8+
This skill helps you work with Jujutsu, a Git-compatible VCS with mutable commits and automatic rebasing.
9+
10+
**Tested with jj v0.37.0** - Commands may differ in other versions.
11+
12+
## Important: Automated/Agent Environment
13+
14+
When running as an agent, **always use `-m` flags** to provide messages inline rather than relying on editor prompts:
15+
16+
```bash
17+
# Always use -m to avoid editor prompts
18+
jj desc -m "message" # NOT: jj desc
19+
jj new -m "message" # NOT: jj new (then describe separately)
20+
jj squash -m "message" # NOT: jj squash (which opens editor)
21+
jj commit -m "message" # NOT: jj commit
22+
```
23+
24+
Editor-based commands will fail in non-interactive environments.
25+
26+
## Core Concepts
27+
28+
### The Working Copy is a Commit
29+
30+
In jj, your working directory is always a commit (referenced as `@`). Changes are automatically snapshotted when you run any jj command. There is no staging area.
31+
32+
### Commits Are Mutable
33+
34+
**CRITICAL**: Unlike git, jj commits can be freely modified. This enables a high-quality commit workflow:
35+
36+
1. Create a commit with your intended message first
37+
2. Make your changes
38+
3. The commit automatically captures your work
39+
4. Refine the commit using `squash`, `split`, or `absorb` as needed
40+
41+
### Change IDs vs Commit IDs
42+
43+
- **Change ID**: A stable identifier (like `tqpwlqmp`) that persists when a commit is rewritten
44+
- **Commit ID**: A content hash (like `3ccf7581`) that changes when commit content changes
45+
46+
Prefer using Change IDs when referencing commits in commands.
47+
48+
## Essential Workflow
49+
50+
### Starting Work: Describe First, Then Code
51+
52+
**Always create your commit message before writing code:**
53+
54+
```bash
55+
# First, describe what you intend to do
56+
jj desc -m "Add user authentication to login endpoint"
57+
58+
# Then make your changes - they automatically become part of this commit
59+
# ... edit files ...
60+
61+
# Check status
62+
jj st
63+
```
64+
65+
### Creating Atomic Commits
66+
67+
Each commit should represent ONE logical change. Use this format for commit messages:
68+
69+
```
70+
"Verb object" - exactly one sentence, no period
71+
72+
Examples:
73+
- "Add validation to user input forms"
74+
- "Fix null pointer in payment processor"
75+
- "Remove deprecated API endpoints"
76+
- "Update dependencies to latest versions"
77+
```
78+
79+
### Viewing History
80+
81+
```bash
82+
# View recent commits
83+
jj log
84+
85+
# View with patches
86+
jj log -p
87+
88+
# View specific commit
89+
jj show <change-id>
90+
91+
# View diff of working copy
92+
jj diff
93+
```
94+
95+
### Moving Between Commits
96+
97+
```bash
98+
# Create a new empty commit on top of current
99+
jj new
100+
101+
# Create new commit with message
102+
jj new -m "Commit message"
103+
104+
# Edit an existing commit (working copy becomes that commit)
105+
jj edit <change-id>
106+
```
107+
108+
## Refining Commits
109+
110+
### Squashing Changes
111+
112+
Move changes from current commit into its parent:
113+
114+
```bash
115+
# Squash all changes into parent
116+
jj squash
117+
118+
# Squash interactively (choose what to move)
119+
jj squash -i
120+
```
121+
122+
### Splitting Commits
123+
124+
Divide a commit that does too much:
125+
126+
```bash
127+
# Split current commit interactively
128+
jj split
129+
130+
# Split a specific commit
131+
jj split -r <change-id>
132+
```
133+
134+
### Absorbing Changes
135+
136+
Automatically distribute changes to the commits that last modified those lines:
137+
138+
```bash
139+
# Absorb working copy changes into appropriate ancestor commits
140+
jj absorb
141+
```
142+
143+
### Abandoning Commits
144+
145+
Remove a commit entirely (descendants are rebased to its parent):
146+
147+
```bash
148+
jj abandon <change-id>
149+
```
150+
151+
## Working with Bookmarks (Branches)
152+
153+
Bookmarks are jj's equivalent to git branches:
154+
155+
```bash
156+
# Create a bookmark at current commit
157+
jj bookmark create my-feature
158+
159+
# Move bookmark to a different commit
160+
jj bookmark move my-feature -r <change-id>
161+
162+
# List bookmarks
163+
jj bookmark list
164+
165+
# Delete a bookmark
166+
jj bookmark delete my-feature
167+
```
168+
169+
## Git Integration
170+
171+
### Working with Existing Git Repos
172+
173+
```bash
174+
# Clone a git repository
175+
jj git clone <url>
176+
177+
# Initialize jj in an existing git repo
178+
jj git init --colocate
179+
```
180+
181+
### Switching Between jj and git (Colocated Repos)
182+
183+
In a colocated repository (where both `.jj/` and `.git/` exist), you can use both jj and git commands. However, there are important considerations:
184+
185+
**Switching to git mode** (e.g., for merge workflows):
186+
```bash
187+
# First, ensure your jj working copy is clean
188+
jj st
189+
190+
# Then checkout a branch with git
191+
git checkout <branch-name>
192+
```
193+
194+
**Switching back to jj mode**:
195+
```bash
196+
# Use jj edit to resume working with jj
197+
jj edit <change-id>
198+
199+
# Or simply run any jj command - it will snapshot the working copy
200+
jj st
201+
```
202+
203+
**Important notes:**
204+
- Git may complain about uncommitted changes if jj's working copy differs from the git HEAD
205+
- Always ensure your work is committed in jj before switching to git
206+
- After git operations, jj will detect and incorporate the changes on next command
207+
208+
### Pushing Changes (Mirrored Repository Context)
209+
210+
**NOTE**: You are likely working on a mirrored clone of the repository, not the original. This mirror has its own remote configured.
211+
212+
When the user asks you to push changes:
213+
214+
```bash
215+
# Push a specific bookmark to the remote
216+
jj git push -b <bookmark-name>
217+
218+
# Example: push the main bookmark
219+
jj git push -b main
220+
```
221+
222+
**Before pushing, ensure:**
223+
1. Your bookmark points to the correct commit (bookmarks don't auto-advance like git branches)
224+
2. The commits are refined and atomic
225+
3. The user has explicitly requested the push
226+
227+
**IMPORTANT**: Unlike git branches, jj bookmarks do not automatically move when you create new commits. You must manually update them before pushing:
228+
229+
```bash
230+
# Move an existing bookmark to the current commit
231+
jj bookmark move my-feature --to @
232+
233+
# Then push it
234+
jj git push -b my-feature
235+
```
236+
237+
If no bookmark exists for your changes, create one first:
238+
239+
```bash
240+
# Create a bookmark at the current commit
241+
jj bookmark create my-feature
242+
243+
# Then push it
244+
jj git push -b my-feature
245+
```
246+
247+
## Handling Conflicts
248+
249+
jj allows committing conflicts - you can resolve them later:
250+
251+
```bash
252+
# View conflicts
253+
jj st
254+
255+
# Resolve conflicts with external tool
256+
jj resolve
257+
258+
# Continue working despite conflicts - jj allows this
259+
```
260+
261+
## Preserving Commit Quality
262+
263+
**IMPORTANT**: Because commits are mutable, always refine them:
264+
265+
1. **Review your commit**: `jj show @` or `jj diff`
266+
2. **Is it atomic?** One logical change per commit
267+
3. **Is the message clear?** "Verb object" format, one sentence
268+
4. **Are there unrelated changes?** Use `jj split` to separate them
269+
5. **Should changes be elsewhere?** Use `jj squash` or `jj absorb`
270+
271+
## Quick Reference
272+
273+
| Action | Command |
274+
|--------|---------|
275+
| Describe commit | `jj desc -m "message"` |
276+
| View status | `jj st` |
277+
| View log | `jj log` |
278+
| View diff | `jj diff` |
279+
| New commit | `jj new -m "message"` |
280+
| Edit commit | `jj edit <id>` |
281+
| Squash to parent | `jj squash` |
282+
| Split commit | `jj split` |
283+
| Auto-distribute | `jj absorb` |
284+
| Abandon commit | `jj abandon <id>` |
285+
| Create bookmark | `jj bookmark create <name>` |
286+
| Push bookmark | `jj git push -b <name>` |
287+
288+
## Best Practices Summary
289+
290+
1. **Describe first**: Set the commit message before coding
291+
2. **One change per commit**: Keep commits atomic and focused
292+
3. **Use change IDs**: They're stable across rewrites
293+
4. **Refine commits**: Leverage mutability for clean history
294+
5. **Embrace the workflow**: No staging area, no stashing - just commits

0 commit comments

Comments
 (0)