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

Git submodule gets deleted and cannot be restored #5246

Closed
TheZoq2 opened this issue Jan 3, 2025 · 8 comments
Closed

Git submodule gets deleted and cannot be restored #5246

TheZoq2 opened this issue Jan 3, 2025 · 8 comments
Labels
🐛bug Something isn't working

Comments

@TheZoq2
Copy link

TheZoq2 commented Jan 3, 2025

Description

I'm not sure if this is the same problem as #5013 manifesting in a different way, or if this is another issue.

I don't fully understand under what cases this problem occurs, but it sometimes I end up in states where a git submodule is shown as deleted by jj, and at that point it seems impossible to restore.

Steps to Reproduce the Problem

I have seen 2 ways to reproduce it. First, it seems like if you switch over to a commit that doesn't have a submodule, then go back to one that has it, it is untracked.

Set up a repo with a submodule

git init submodule_test
cd submodule_test
touch file
git add file
git commit -m "Add file"
git submodule add https://gitlab.com/TheZoq2/vatch
git commit -m "Add submodule"

Colocate a jj repo

jj git init --colocate

JJ status shows everything is fine

> jj st

The working copy is clean
Working copy : mmowqtyp d0d3a9ba (empty) (no description set)
Parent commit: xrxmuuou 50b18546 main | Add submodule

and log

@  tqssylnz [email protected] 2025-01-03 10:06:14 bd60c9b9
│  (empty) (no description set)
○  xrxmuuou [email protected] 2025-01-03 10:05:31 main git_head() 50b18546
│  Add submodule
○  vsrutyvw [email protected] 2025-01-03 10:05:06 b4249d95
│  initial commit
◆  zzzzzzzz root() 00000000

Creating a new commit on top of the initial commit shows some warnings

> jj new v
Working copy now at: mxlzqkpq c7068e89 (empty) (no description set)
Parent commit      : vsrutyvw b4249d95 initial commit
Added 0 files, modified 0 files, removed 2 files
Warning: 1 of those updates were skipped because there were conflicting changes in the working copy.
Hint: Inspect the changes compared to the intended target with `jj diff --from c7068e89c95a`.
Discard the conflicting changes with `jj restore --from c7068e89c95a`.

So far, everything is fine (Though maybe that conflicting changes warning is relevant here 🤔)

Now, switching back to a commit that has the problem

> jj new x
Working copy now at: xysxpwoq 26095e0d (empty) (no description set)
Parent commit      : xrxmuuou 50b18546 main | Add submodule
Added 2 files, modified 0 files, removed 0 files
Warning: 1 of those updates were skipped because there were conflicting changes in the working copy.
Hint: Inspect the changes compared to the intended target with `jj diff --from 26095e0dce92`.
Discard the conflicting changes with `jj restore --from 26095e0dce92`.

We still get a warning but everything seems fine, But now jj status shows the submodule as deleted

> jj st
Working copy changes:
D vatch
Working copy : xysxpwoq 4351bf01 (no description set)
Parent commit: xrxmuuou 50b18546 main | Add submodule

even though the content is there

> ls vatch
main.v  README.md

Some things I have tried to get the

jj restore does not do anything

> jj restore vatch
Created xysxpwoq 799f776c (empty) (no description set)
Working copy now at: xysxpwoq 799f776c (empty) (no description set)
Parent commit      : xrxmuuou 50b18546 main | Add submodule
Added 1 files, modified 0 files, removed 0 files
Warning: 1 of those updates were skipped because there were conflicting changes in the working copy.
Hint: Inspect the changes compared to the intended target with `jj diff --from 799f776c1da1`.
Discard the conflicting changes with `jj restore --from 799f776c1da1`.

The diff command it suggests shows the submodule as deleted, restore --from as it suggests also does not work

git status is empty

Removing the submodule and then re-adding it similarly does not resolve the problem

> git rm vatch
> git submodule add --force https://gitlab.com/TheZoq2/vatch
> jj st
Working copy changes:
D vatch
Working copy : xysxpwoq 8a39749a (no description set)
Parent commit: xrxmuuou 50b18546 main | Add submodule

Expected Behavior

Ideally, the submodule shouldn't get deleted, and if it does there should be a way to restore it

Actual Behavior

The submodule cannot get restored

Specifications

  • Platform: Arch Linux
  • Version: 0.25.0
@TheZoq2
Copy link
Author

TheZoq2 commented Jan 3, 2025

Ok, I thought I figured out a workaround but it seems to be more subtle than that
In my broken state I created a new commit on top of x, the commit that added the submodule

> jj new x
Working copy now at: pztmppkt a407b1ae (empty) (no description set)
Parent commit      : xrxmuuou b9609ab2 main | Add submodule
Added 2 files, modified 0 files, removed 0 files
Warning: 1 of those updates were skipped because there were conflicting changes in the working copy.
Hint: Inspect the changes compared to the intended target with `jj diff --from a407b1ae5cba`.
Discard the conflicting changes with `jj restore --from a407b1ae5cba`.
> /tmp/submodule_test ♦ ➔ jj st
Working copy changes:
D vatch
Working copy : pztmppkt 6b2228ca (no description set)
Parent commit: xrxmuuou b9609ab2 main | Add submodule

I then created an empty commit using git

> /tmp/submodule_test ♦ ➔ g c --allow-empty
[detached HEAD fb2bb8e] dummy
> /tmp/submodule_test ♦ ➔ jj st
ignoring git submodule at "vatch"
Reset the working copy parent to the new Git HEAD.
The working copy is clean
Working copy : kzuzwmns d6ce9d68 (empty) (no description set)
Parent commit: snzsxumw fb2bb8e3 (empty) dummy
> /tmp/submodule_test ♦ ➔ jj
Hint: Use `jj -h` for a list of available commands.
Run `jj config set --user ui.default-command log` to disable this message.
@  kzuzwmns [email protected] 2025-01-03 10:28:07 d6ce9d68
│  (empty) (no description set)
○  snzsxumw [email protected] 2025-01-03 10:28:03 git_head() fb2bb8e3
│  (empty) dummy
│ ○  pztmppkt [email protected] 2025-01-03 10:27:55 6b2228ca
├─╯  (no description set)
○  xrxmuuou [email protected] 2025-01-03 10:25:00 main b9609ab2
│  Add submodule
○  vsrutyvw [email protected] 2025-01-03 10:05:06 b4249d95
│  initial commit
◆  zzzzzzzz root() 00000000

I then squashed that commit down onto x

> /tmp/submodule_test ♦ ➔ jj edit s
Working copy now at: snzsxumw fb2bb8e3 (empty) dummy
Parent commit      : xrxmuuou b9609ab2 main | Add submodule
> /tmp/submodule_test ♦ ➔ jj st
The working copy is clean
Working copy : snzsxumw fb2bb8e3 (empty) dummy
Parent commit: xrxmuuou b9609ab2 main | Add submodule
/tmp/submodule_test ♦ ➔ jj
Hint: Use `jj -h` for a list of available commands.
Run `jj config set --user ui.default-command log` to disable this message.
@  snzsxumw [email protected] 2025-01-03 10:28:03 fb2bb8e3
│  (empty) dummy
│ ○  pztmppkt [email protected] 2025-01-03 10:27:55 6b2228ca
├─╯  (no description set)
○  xrxmuuou [email protected] 2025-01-03 10:25:00 main git_head() b9609ab2
│  Add submodule
○  vsrutyvw [email protected] 2025-01-03 10:05:06 b4249d95
│  initial commit
◆  zzzzzzzz root() 00000000
/tmp/submodule_test ♦ ➔ jj squash

Finally, I abandoned the extra commit that got added for some reason I don't understand

jj abandon p
Abandoned commit pztmppkt e39d8e96 (no description set)

And now, things work as expected

/tmp/submodule_test ♦ ➔ jj st
The working copy is clean
Working copy : tnrkvrvw 2aedffb4 (empty) (no description set)
Parent commit: xrxmuuou 95ac33d0 main | Add submodule

The weird thing though is that now my reproducer doesn't reproduce the issue anymore, I can hop between x and v without having the submodule diff

And the diff for x now only shows the change to .gitmodules

> jj show x

Commit ID: a32edb6774b3582bc10716d69c810370608b0aa2
Change ID: xrxmuuouqupxxwmkkosovwuuntxqqtlq
Bookmarks: main main@git
Author   : TheZoq2 <[email protected]> (2025-01-03 10:05:31)
Committer: TheZoq2 <[email protected]> (2025-01-03 10:33:02)

    Add submodule

    Test

    dummy

Added regular file .gitmodules:
        1: [submodule "vatch"]
        2:      path = vatch
        3:      url = https://gitlab.com/TheZoq2/vatch

@TheZoq2
Copy link
Author

TheZoq2 commented Jan 3, 2025

One more update: That workaround didn't work right away in my real world repo, to make it work I had to git switch -d <commit where the submodule was removed> then manually re-add the submodule

@PhilipMetzger PhilipMetzger added the 🐛bug Something isn't working label Jan 3, 2025
@TheZoq2
Copy link
Author

TheZoq2 commented Jan 5, 2025

And another case of the same or a similar bug:

Cloning https://gitlab.com/spade-lang/spade/ then jj git init --colocate deletes the submodule, same if I first git submodule update --init --recursive

Edit: I wonder if this is related to submodules in directories. This works as expected

touch file \
	&& git add file \
	&& git commit -m "init" \
	&& git submodule add [email protected]:jj-vcs/jj.git \
	&& git commit -m "Add submodule" \
	&& jj git init --colocate

While this results in a stuck submodule

touch file \
	&& git add file \
	&& git commit -m "init" \
	&& mkdir dir \
	&& cd dir \
	&& git submodule add [email protected]:jj-vcs/jj.git \
	&& git commit -m "Add submodule"
	&& cd .. \
	&& jj git init --colocate
`

@yuja
Copy link
Contributor

yuja commented Jan 6, 2025

I don't follow the other comments, but in the original steps to reproduce:

jj new x
Working copy now at: xysxpwoq 26095e0d (empty) (no description set)
Parent commit : xrxmuuou 50b18546 main | Add submodule
Added 2 files, modified 0 files, removed 0 files
Warning: 1 of those updates were skipped because there were conflicting changes in the working copy.
Hint: Inspect the changes compared to the intended target with jj diff --from 26095e0dce92.
Discard the conflicting changes with jj restore --from 26095e0dce92.

At this point, unmanaged vatch directory exist, so jj new skipped to update the path (to "submodule" state.) That's why the submodule path is marked as deleted, I think. You'll need to remove the directory, and run jj abandon or jj restore to start over.

It's not fancy, but that's the current state of submodule support. Submodule contents aren't managed by jj, so they have to be updated by user.

@TheZoq2
Copy link
Author

TheZoq2 commented Jan 6, 2025

Yep you're right, abandon in that situation did work, not sure why I didn't try that.

The followup comments are as far as I can tell an actual bug though. As soon as I co-locate a repo with a submodule in a subdirectory with

touch file \
	&& git add file \
	&& git commit -m "init" \
	&& mkdir dir \
	&& cd dir \
	&& git submodule add [email protected]:jj-vcs/jj.git \
	&& git commit -m "Add submodule" \
	&& cd .. \
	&& jj git init --colocate

I end up with a deleted dir/jj which I cannot get rid of.

I've been trying to investigate this issue to see if I can solve it and I think I've at least discovered a potential cause.

Skipping a bunch of debugging steps I did before getting here, I noticed that in snapshot_working_copy on line 1853 new_tree_id is a tree which is missing the submodule while wc_commit.tree_id does not.

new_tree_id comes from snapshot which gets a deleted file from the visitor directory_visitorat line 1030 inlib/src/local_working_copy.rs`

This seems to come down to process_dir_entry in the same file taking the visit_tracked_files branch on line 1253. visit_tracked_files. visit_tracked_files gets the submodule from file_states but on line 1335

            if let Some(new_file_state) = metadata.as_ref().and_then(file_state) {

it gets None since file_state assumes the file to be a file, not a directory.

@yuja
Copy link
Contributor

yuja commented Jan 7, 2025

touch file \
	&& git add file \
	&& git commit -m "init" \
	&& mkdir dir \
	&& cd dir \
	&& git submodule add [email protected]:jj-vcs/jj.git \
	&& git commit -m "Add submodule" \
	&& cd .. \
	&& jj git init --colocate

It works for me, but maybe you disabled snapshot.auto-track? Appears that the "ignored directory" code path doesn't have a workaround for submodule dirs.

@TheZoq2
Copy link
Author

TheZoq2 commented Jan 7, 2025

Hmm, yes I did disable auto-track. It still seems like there is a bug in here but re-enabling auto-track does seem like a good workaround

@yuja
Copy link
Contributor

yuja commented Jan 7, 2025

Yes, it's a bug of visit_tracked_files().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants