Skip to content
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

Working copy changes are lost when a remote branch is deleted and git fetch has run #2876

Closed
jennings opened this issue Jan 23, 2024 · 6 comments
Assignees

Comments

@jennings
Copy link
Collaborator

jennings commented Jan 23, 2024

Description

Suppose you're working in a colocated repo and:

  • A remote branch has been deleted
  • The working copy is one of the changes that were part of the deleted branch
  • The working copy has been modified, but jj has not been run yet so no snapshot has been taken
  • git fetch --prune is run (in my case, my editor periodically fetches)

Then, the edits in the working copy are lost when jj abandons the changes. The changes were never added to a snapshot, so they aren't available in the operation log.

Steps to Reproduce the Problem

Here is a script that reproduced the problem. The branch "feature" is the one to be deleted from the remote.

# SETUP: Create the upstream
mkdir repro-bug
cd repro-bug
git init --bare upstream.git
git init someone-elses-repo -b main
cd someone-elses-repo
echo "hello" > file
git add file
git commit -m "initial"
git remote add origin ../upstream.git
git push -u origin main

# SETUP: Create a side branch
git checkout -b feature
echo "goodbye" >> file
git commit -am "change file"
git push -u origin feature
cd ..

# Create the local repo and edit the tip of the branch "feature"
jj git clone --colocate upstream.git local
cd local
jj branch track feature@origin
jj edit feature

# Delete the branch from the remote
cd ../someone-elses-repo
git push origin :feature
cd ../local

# Edit the working copy and git fetch
echo "hello again" > file
# I need this because git doesn't understand \\?\ paths on Windows
# git remote set-url origin ../upstream.git
git fetch
# git remote set-url origin '\\?\C:\Users\StephenJennings\repro-bug\upstream.git'
jj

Expected Behavior

The working copy still contains "hello again" in file.

Actual Behavior

The working copy contains only "hello" and no change contains "hello again".

Specifications

  • Platform: Windows
  • Version: 0.13.0
@ilyagr
Copy link
Collaborator

ilyagr commented Jan 24, 2024

Do I understand correctly that your modifications are still there after the "git fetch" (penultimate command in your demo), but jj discards them?

@jennings
Copy link
Collaborator Author

Yes, I’m not sure how they would be removed at that point since git fetch doesn’t modify the working copy, just the object store and remote tracking refs.

My hypothesis is that the automatic jj git import is happening before a snapshot would, so jj never learns about the modified working copy. Then it abandons the changes that were in the deleted branch and overwrites the files on disk with whatever @ moves to.

@jennings
Copy link
Collaborator Author

jennings commented Jan 24, 2024

Thinking about it more, I can probably simplify the reproduction by removing the remote. I’m guessing that deleting a local git branch then running jj would trigger the same thing.

@yuja
Copy link
Collaborator

yuja commented Jan 24, 2024

the automatic jj git import is happening before a snapshot would,

Correct, and jj would probably think the HEAD was moved externally (so reset the working copy.) Perhaps, maybe_snapshot() will have to do

  1. handle externally moved HEAD
  2. snapshot
  3. import refs

@yuja
Copy link
Collaborator

yuja commented Jan 24, 2024

simplify the reproduction by removing the remote

git init repo
cd repo
jj init --git-repo=.
echo 1 > file
jj branch create feature
git branch -D feature
echo 2 > file
jj status
cat file

btw, the original repro script needs git fetch --prune.

@jennings jennings changed the title Working copy changes are lost when a remote branch is deleted and git fetch runs Working copy changes are lost when a remote branch is deleted and git fetch has run Jan 24, 2024
@jennings
Copy link
Collaborator Author

Ah, great, that’s much easier to understand. When it happened to me, VSCode had done the fetch so I wrote the reproduction as similar as I could to my real situation.

btw, the original repro script needs git fetch --prune.

You’re right, I forgot that I have automatic prune enabled.

@yuja yuja self-assigned this Jan 25, 2024
yuja added a commit to yuja/jj that referenced this issue Jan 26, 2024
Since import_git_refs() may check out new working-copy commit, it shouldn't be
triggered before the snapshot.

Fixes martinvonz#2876
@yuja yuja closed this as completed in 3207009 Jan 26, 2024
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Feb 13, 2024
## [0.14.0] - 2024-02-07

### Deprecations

* `jj checkout` and `jj merge` are both deprecated; use `jj new` instead to
  replace both of these commands in all instances.

  **Rationale**: `jj checkout` and `jj merge` both implement identical
  functionality, which is a subset of `jj new`. `checkout` creates a new working
  copy commit on top of a single specified revision, i.e. with one parent.
  `merge` creates a new working copy commit on top of *at least* two specified
  revisions, i.e. with two or more parents.

  The only difference between these commands and `jj new`, which *also* creates
  a new working copy commit, is that `new` can create a working copy commit on
  top of any arbitrary number of revisions, so it can handle both the previous
  cases at once. The only actual difference between these three commands is the
  command syntax and their name. These names were chosen to be familiar to users
  of other version control systems, but we instead encourage all users to adopt
  `jj new` instead; it is more general and easier to remember than both of
  these.

  `jj checkout` and `jj merge` will no longer be shown as part of `jj help`, but
  will still function for now, emitting a warning about their deprecation.

  **Deadline**: `jj checkout` and `jj merge` will be deleted and are expected
  become a **hard error later in 2024**.

* `jj init --git` and `jj init --git-repo` are now deprecated and will be removed
  in the near future.

  Use `jj git init` instead.


### Breaking changes

* (Minor) Diff summaries (e.g. `jj diff -s`) now use `D` for "Deleted" instead
  of `R` for "Removed". @joyously pointed out that `R` could also mean
  "Renamed".

* `jj util completion` now takes the shell as a positional argument, not a flag.
  the previous behavior is deprecated, but supported for now. it will be removed
  in the future.

### New features

* `jj util completion` now supports powershell and elvish.

* Official binaries for macOS running on Apple Silicon (`aarch64-apple-darwin`)
  are now available, alongside the existing macOS x86 binaries.

* New `jj op abandon` command is added to clean up the operation history. Git
  refs and commit objects can be further compacted by `jj util gc`.

* `jj util gc` now removes unreachable operation, view, and Git objects.

* `jj branch rename` will now warn if the renamed branch has a remote branch, since
  those will have to be manually renamed outside of `jj`.

* `jj git push` gained a `--tracked` option, to push all the tracked branches.

* There's now a virtual root operation, similar to the [virtual root
  commit](docs/glossary.md#root-commit). It appears at the end of `jj op log`.

* `jj config list` gained a `--include-overridden` option to allow
  printing overridden config values.

* `jj config list` now accepts `--user` or `--repo` option to specify
  config origin.

* New `jj config path` command to print the config file path without launching
  an editor.

* `jj tag list` command prints imported git tags.

* `jj next` and `jj prev` now prompt in the event of the next/previous commit
  being ambiguous, instead of failing outright.

* `jj resolve` now displays the file being resolved.

* `jj workspace root` was aliased to `jj root`, for ease of discoverability

* `jj diff` no longer shows the contents of binary files.

* `jj git` now has an `init` command that initializes a git backed repo.

* New template function `surround(prefix, suffix, content)` is added.

### Fixed bugs

* Fixed snapshots of symlinks in `gitignore`-d directory.
  [#2878](martinvonz/jj#2878)

* Fixed data loss in dirty working copy when checked-out branch is rebased or
  abandoned by Git.
  [#2876](martinvonz/jj#2876)
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

No branches or pull requests

3 participants