-
Notifications
You must be signed in to change notification settings - Fork 344
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
jj git fetch
with multiple remotes can abandon reachable commits (and rebase reachable descendants)
#4920
Comments
This is probably happening because git::fetch is called one remote at a time; Within
Maybe we could collate changed_refs for all remotes and call import_some_refs only after all remotes have been downloaded? |
As discussed on IRC, changing the behavior would mean that |
It's surprising to me that the order of remotes matters when fetching. If I have two remotes A and B, I would expect all of these commands to behave the same: jj git fetch --all-remotes
jj git fetch --remote A --remote B
jj git fetch --remote B --remote A |
Do you mean s/that/if/ ? Or is there an existing case where they behave differently? (I'm not saying there isn't. I just haven't thought of one.) |
I thought this issue was an example, where |
Oh, of course. It's at least close to that behavior. If you fetch first from the remote where the branch was deleted, then your local commit would be rebased off it it and then when you fetch from the other remote, the abandoned commits would be added back. If you instead fetched from the other remote first, then you would get some new commits from the remote and the next fetch would rebase your local commits and the new remote commits off of the abandoned commits. |
I would expect this to be the correct behavior, the order mattering would be massively unintuitive
Part of the problem is that fetches performed in one command are one jj operation. |
From what little I know of jj's internals, this seems like the obvious, correct solution, and would give the expected behavior where order doesn't matter, and changes are abandoned if and only if they are not reachable from any bookmark in the fresh tree. |
…rectly. * Make the new `GitFetch` api public. * Rewrite all tests that used `git::fetch*` to use the new API. One interesting artifact of the new API is that it holds onto a reference of the `tx.repo_mut()`, so the GitFetch object needs to fall go of scope completely before we can make any other mutable calls to `tx`. * Delete the `git::fetch` * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4923 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. Fixes: #4920
…rectly. * Make the new `GitFetch` api public. * Rewrite all tests that used `git::fetch*` to use the new API. One interesting artifact of the new API is that it holds onto a reference of the `tx.repo_mut()`, so the GitFetch object needs to fall go of scope completely before we can make any other mutable calls to `tx`. * Delete the `git::fetch` * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4920 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. Fixes: #4920
* Make the new `GitFetch` api public. * Rewrite all tests that used `git::fetch*` to use the new API. One interesting artifact of the new API is that it holds onto a reference of the `tx.repo_mut()`, so the GitFetch object needs to fall go of scope completely before we can make any other mutable calls to `tx`. * Delete the `git::fetch` * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4920 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. Fixes: #4920
* Make the new `GitFetch` api public. * Rewrite all tests that used `git::fetch*` to use the new API. One interesting artifact of the new API is that it holds onto a reference of the `tx.repo_mut()`, so the GitFetch object needs to fall go of scope completely before we can make any other mutable calls to `tx`. * Delete the `git::fetch` * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4920 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. Fixes: #4920
* Make the new `GitFetch` api public. * Move `git::fetch` to `lib/tests/test_git.rs` as `git_fetch`, to minimize churn in the tests. Update test call sites to use `git_fetch` * Delete the `git::fetch` from `lib/src/git.rs`. * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4920 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. * Add test for the race condition. Fixes: #4920
* Make the new `GitFetch` api public. * Move `git::fetch` to `lib/tests/test_git.rs` as `git_fetch`, to minimize churn in the tests. Update test call sites to use `git_fetch` * Delete the `git::fetch` from `lib/src/git.rs`. * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4920 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. * Add test for the race condition. Fixes: #4920
* Make the new `GitFetch` api public. * Move `git::fetch` to `lib/tests/test_git.rs` as `git_fetch`, to minimize churn in the tests. Update test call sites to use `git_fetch` * Delete the `git::fetch` from `lib/src/git.rs`. * Update `jj git clone` and `git_fetch` in `cli/src/git_utils.rs` to use the new api directly. Removing one redundant layer of indirection. * This fixes #4920 as it first fetches from all remotes before `import_refs()` is called, so there is no race condition if the same commit is treated differently in different remotes specified in the same command. * Add test for the race condition. Fixes: #4920
Description
jj abandons work from pruned PR branches and mangles history if the pr repo is fetched before the origin.
Steps to Reproduce the Problem
Minimal reproduction:
Expected Behavior
Bookmarks are updated, repo has state consistent with both remotes.
Fetch never, under any circumstances modifies any commits. Abandons should only happen for commits that are unreachable after all fetches.
Actual Behavior
b is pulled first, the commit is marked to be abandoned
c is pulled, referencing the lost commit
jj blindly performs the abandon, modifying history such that 'work' is lost.
Specifications
Linux ceres 6.6.53 #1-NixOS SMP PREEMPT_DYNAMIC Mon Sep 30 14:25:15 UTC 2024 x86_64 GNU/Linux
jj 0.22.0
The text was updated successfully, but these errors were encountered: