Skip to content

Handling divergent changes

What are divergent changes?

A divergent change occurs when multiple visible commits have the same change ID.

Normally, when commits are rewritten, the original version (the "predecessor") becomes hidden and the new commit (the "successor") is visible. Thus, only one commit with a given change ID is visible at a time.

But, a hidden commit can become visible again. This can happen if:

  • A visible descendant is added locally. For example, jj new REV will make REV visible even if it was hidden before.

  • A visible descendant is fetched from a remote. If the hidden commit was pushed to a remote, others may base new commits off of them. When their new commits are fetched, their visibility makes the hidden commit visible again.

  • It is made the working copy. jj edit REV will make REV and all its ancestors visible if it wasn't already.

  • Some other operations make hidden commits visible. For example, adding a bookmark to a hidden commit makes it visible with the assumption that you are now working with that commit again.

Divergent changes also occur if two different users or processes amend the same change, creating two visible successors. This can happen when:

  • Another author modifies commits in a branch that you have also modified locally.

  • You perform operations on the same change from different workspaces of the same repository.

  • Two programs modify the repository at the same time. For example, you run jj describe and, while writing your commit description, an IDE integration fetches and rebases the branch you're working on.

How do I resolve divergent changes?

When you encounter divergent changes, you have several strategies to choose from. The best approach depends on whether you want to keep the content from one commit, both commits, or merge them together.

Note that revsets must refer to the divergent commit using its commit ID since the change ID is ambiguous.

Strategy 1: Abandon one of the commits

If one of the divergent commits is clearly obsolete or incorrect, simply abandon it:

# Abandon the unwanted commit using its commit ID
jj abandon <unwanted-commit-id>

# You can abandon several at once with:
# jj abandon xyz wxy vwx
# jj abandon xyz::

This is the simplest solution when you know which version to keep.

Strategy 2: Duplicate and abandon

If you want to keep both versions as separate changes with different change IDs, you can duplicate one of the commits to generate a new change ID, then abandon the original:

# Duplicate one of the commits to create a new change ID
jj duplicate <commit-id>

# Abandon the original commit
jj abandon <commit-id>

This preserves both versions of the content while resolving the divergence.

Strategy 3: Squash the commits together

When you want to combine the content from both divergent commits:

# Squash one commit into the other
jj squash --from <source-commit-id> --into <target-commit-id>

This combines the changes from both commits into a single commit. The source commit will be abandoned.

Strategy 4: Ignore the divergence

Divergence isn't an error. If the divergence doesn't cause immediate problems, you can leave it as-is. If both commits are part of immutable history, this may be your only option.

However, it can be inconvenient since you cannot refer to divergent changes unambiguously using their change ID.