Skip to content

docs: Add guide for handling divergent changes #7061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jennings
Copy link
Contributor

Divergent changes are so frequently asked that I think it deserves more explanation than a FAQ entry can give it.

I think making a new "Guides" section and putting this there makes us better able to explain what's going on.

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added/updated tests to cover my changes

@jennings jennings requested a review from a team as a code owner July 24, 2025 04:50
@jennings jennings force-pushed the jennings/kplkzlnyvpto branch from c4642db to 97a57fe Compare July 24, 2025 05:17
## What are divergent changes?

A [divergent change][glossary_divergent_change] occurs when multiple visible
commits have the same change ID.
Copy link

@zx8 zx8 Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a link to https://jj-vcs.github.io/jj/prerelease/glossary/#visible-commits?

When I was new to jj (coming from git), I found it tricky to navigate/understand the docs because there was a bunch of new terminology that seemed to be assumed knowledge, so it'd be handy to linkify these sorts of things.

visible even if it was hidden before.

- It is made the working copy. `jj edit REV` will make `REV` visible if it
wasn't already.
Copy link

@apoelstra apoelstra Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 97a57fe:

We should add the case where a new ref is imported from git, e.g. by the user running git fetch or otherwise directly manipulating the git repo. For me this is the most common source of divergent change IDs, and it's especially confusing because "I didn't do anything, I just git fetched!", which in pure git is one of the least destructive things you can do.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(See #4388 in case you are wondering why somebody would use git fetch. This is a very common workflow with Github and Gitlab, which provide non-branch refs for every PR, saving you the work of adding every contributor's fork as a remote.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this sound?

  • 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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds great to me! I didn't realize that this was the specific mechanism by which my fetches were causing me grief.

I kinda think that jj itself should help with this. by noticing when previously-hidden commits become visible again. (And distinguishing between commits that were hidden manually with abandon and those that were hidden implicitly by just updating a change). Though this is out of scope for a docs change, of course.

Copy link
Contributor

@PhilipMetzger PhilipMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, mostly left some minor nits with discussion points

Comment on lines +12 to +15
But, a hidden commit can become visible again. This can happen if:

- A visible descendant is added. For example, `jj new REV` will make `REV`
visible even if it was hidden before.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if you want to be complete here, the bookmark commands also should be mentioned

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

- Multiple people edit the same change simultaneously in different repositories.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: expand this to mention to mention a coworker working on the same branch and then re-pushing, since many don't understand that as a rewrite

Copy link
Contributor Author

@jennings jennings Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to a coworker appending a new commit to your branch (as opposed to amending a commit)? Do you think this suggestion would address that too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean this case here: #7004

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this sound if I replace all the bullet points with this?

  • 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that should be good enough

@@ -540,15 +540,6 @@ with something like `jj desc -m "Revert the merge of D into B`. Now, commit `@`
undoes the merge of `D` into `B`. If necessary, you can now rebase it
elsewhere, e.g. `jj rebase -r @ -d main`.

### How do I deal with divergent changes ('??' after the [change ID])?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should leave the FAQ entry, and link to the new doc for more details.

Copy link
Contributor Author

@jennings jennings Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally did that, but then realized we keep old versions of the documentation published.

Removing this question will only affect /latest/ and /prerelease/.

If someone needs a permanent link to documentation, I think they really should be linking to a specific version.

It also seemed untenable to keep old FAQ questions around forever for this purpose.

What do others think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this question will only affect /latest/ and /prerelease/.

No, the point is that someone reading the FAQ will find the divergent answer, and then follow the link to the new doc to get all the details. Two ways to discover the answer are better than one. Just to note, I'm not concerned about versions of the docs, just that the info is discoverable.

Copy link
Contributor

@PhilipMetzger PhilipMetzger Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @ilyagr's opinion on that should matter. I have no preference here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think people often link to the /latest version of the docs. for example, most links inside jj's source code are to /latest.

Joy's point also seems reasonable to me; this would make the article more discoverable, and I don't see much harm in the FAQ question remaining.

So, I'd keep the question, even if it becomes a stub.

jj log -r 'divergent()'

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 97a57fe:

I think this instance of jj abandon (the one right after jj log -r 'divertgent()', since Github display doesn't have enough context) should illustrate that you can provide multiple commit IDs. If you abandon them one at a time, descendants (which you intend to abandon anyway) get rebased and chenge their commit IDs from under you, and get conflicts.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one below (in "duplicate and abandon") I think should also do this: it should probably illustrate duplicating commits one by one, for simplicity's sake, but then abandon them all at once.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I don't feel strongly about this -- if you're unsure at all you can just ignore me. This PR is super valuable and I don't mean to hang it up or waste mental energy on minutae.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants