| name | jj-workflow |
| description | Guidelines and procedures for using Jujutsu (jj) in KHI, including change management, workspace isolation, pushing commits with auto-generated bookmarks, addressing PR review feedback without squashing, and resolving conflicts incrementally from oldest to newest commit. |
KHI Jujutsu (jj) Workflow Guidelines
This guide outlines the standard version control workflow for working on the Kubernetes History Inspector (KHI) project using Jujutsu (jj).
1. Core Principles
- Prefer Jujutsu (
jj) Commands: Always use jj commands instead of raw Git commands whenever possible.
- Working Copy is Always a Change: In Jujutsu, the working copy (
@) is treated as an in-progress change/commit at all times.
- Describe vs. New:
jj describe -m "...": Updates the commit message of the current change (@). It does not create a new commit.
jj new: Commits and freezes the current change, then creates a new, empty working-copy change (@) on top of it.
- Task Boundaries: Always run
jj new upon completing a logical unit of work or before switching tasks.
- Workspace Isolation: Always make changes strictly within your assigned workspace. You may inspect or reference other workspaces, but never modify files or commit changes in another workspace.
- Explicit Approval for Pushes: Never execute
jj git push or create remote modifications without explicit user approval.
2. Workspace Isolation
[!IMPORTANT]
Never modify files or state in other workspaces.
- Inspecting or referencing other workspaces (e.g., viewing files or reading logs) is allowed.
- However, you must NEVER modify, edit, or create files in another workspace.
- All changes, commits, and development work must take place strictly within your assigned workspace.
3. Standard Development Flow
Starting a New Change
Before starting work on a new feature or bugfix, verify that your working copy is clean with jj status, then create a new change:
jj new -m "feat(scope): short description"
Developing and Reviewing Changes
Edit files as needed. Check your progress and inspect changes:
jj status
jj diff
Update the commit message as work evolves:
jj describe -m "feat(scope): detailed message"
Testing and Formatting
Before finalizing any commit or boundary, execute KHI test and verification commands:
make pre-commit
make lint-go && make lint-web
make test-go && make test-web
Freezing the Change
When the task is complete and verified:
jj new
This freezes your completed change into the commit graph history (@-) and moves your working copy (@) to a new empty change.
4. Pushing Changes & Remote Bookmarks
[!IMPORTANT]
Do not invent custom remote branch names manually.
Always let jj generate and manage bookmark names automatically.
When you need to push a change to the remote repository for review or PR creation:
jj git push -c @
- Jujutsu automatically assigns a unique bookmark name (e.g.,
push-qpzqrvsmmnvr) and pushes it to the remote Git repository (origin).
- Use this auto-generated bookmark name as the head branch when opening a Pull Request on GitHub.
- If the change already has a tracked remote bookmark, update it with:
jj git push --tracked
5. Addressing PR Review Feedback (No Squashing)
[!IMPORTANT]
Do NOT squash review fixes into the original commit (jj squash is forbidden here).
Reviewers must be able to inspect incremental diffs across review rounds. Always preserve review iteration history.
When review comments require code changes:
-
Create a New Child Revision on the PR Commit:
Start a new change directly on top of the PR commit:
jj new
jj new <pr-bookmark-or-commit>
-
Apply the Fixes:
Modify the source files to address the reviewer feedback.
-
Verify and Format:
Run formatters and tests to ensure no regressions:
make format-go && make format-web
make test-go && make test-web
-
Set a Descriptive Commit Message:
jj describe -m "fix(scope): address review comments on XYZ"
-
Advance or Move the PR Bookmark to the New Commit:
Update the PR bookmark to track the newly created fix commit (@):
jj bookmark advance
jj bookmark move <pr-bookmark-name> --to @
-
Push the Updated PR:
jj git push
The GitHub PR will automatically show the new incremental commit, allowing reviewers to verify changes easily.
6. Conflict Resolution Workflow (Oldest to Newest)
In Jujutsu, merge and rebase conflicts do not abort operations. Instead, conflicts are recorded as first-class states directly on the affected commits.
[!IMPORTANT]
Always resolve conflicts starting from the oldest conflicted commit first.
Resolving the oldest commit frequently resolves downstream conflicts automatically and prevents cascading conflict cycles.
Step-by-Step Resolution Procedure
-
Identify Conflicted Commits:
List all revisions currently in a conflicted state:
jj log -r 'conflicts()'
-
Select the Oldest Conflicted Commit:
Examine the commit graph and pick the oldest (root-most) ancestor among the conflicted revisions. Let this be <conflicted-rev>.
-
Spawn a Working Copy on the Conflicted Commit:
Create a new child revision directly on the conflicted commit:
jj new <conflicted-rev>
The working copy (@) now contains the conflicting files with conflict markers (<<<<<<<, >>>>>>>, %%%%%%%).
-
Resolve Conflict Markers:
Edit all conflicting files and resolve the markers manually to achieve the desired clean state.
-
Verify the Resolution:
Run linters and tests to verify that the resolution builds cleanly and passes all test suites:
make lint-go && make lint-web
make test-go && make test-web
-
Squash the Resolution into the Conflicted Commit:
Once all tests pass, squash the working copy back into the parent commit (<conflicted-rev>):
jj squash
This moves the clean, resolved content into <conflicted-rev>, clearing its conflicted state.
-
Repeat for Remaining Downstream Conflicts:
Jujutsu automatically rebases any child commits on top of the resolved commit. Re-check for remaining conflicts:
jj log -r 'conflicts()'
If any commits still have conflicts, repeat steps 2 through 6 for the next oldest conflicted commit until conflicts() is completely empty.
7. Pre-flight Checklist
Before finalizing any task or pushing to a remote repository: