{"thread":{"id":"54986","subject":"bug: checkout --recurse-submodules discard uncommited changes in submodule","startedAt":"2021-01-14T08:52:28Z","lastAt":"2021-01-14T16:41:20Z","messageCount":3,"participants":["Kevin Bernard","Philippe Blain"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"414342","messageId":"570e77a07f0b4d4ea09307e5fa819d6f@fiveco.ch","threadId":"54986","inReplyTo":null,"subject":"bug: checkout --recurse-submodules discard uncommited changes in submodule","fromName":"Kevin Bernard","fromEmail":"kevin.bernard@fiveco.ch","sentAt":"2021-01-14T08:35:47Z","receivedAt":"2021-01-14T08:52:28Z","isPatch":false,"sender":{"key":"kevin.bernard@fiveco.ch","avatar":null},"body":"Thank you for filling out a Git bug report!\nPlease answer the following questions to help us understand your issue.\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\nMake a git repository with a submodule in it.\nMake two different commits in the main repository with two different versions of\nthe submodule, one of them is the head of the branch.\nCheckout the head of the branch in the main repository, and make a submodule update.\nMake a modification, do not commit it, in a submodule file that will not result\nin a \"error: Your local changes to the following files would be overwritten by\ncheckout\" when the other version of the library will be checked out.\nGo back to the main repository and make a checkout of the other commit with the\nswitch --recurse-submodules.\n\nWhat did you expect to happen? (Expected behavior)\nThe checkout with the switch --recurse-submodules should fail when there are\nuncommitted changes in the submodule.\n\nWhat happened instead? (Actual behavior)\nUncommitted changes in the submodule are discarded without any notifications.\n\nWhat's different between what you expected and what actually happened?\nLoss of the uncommitted changes in the submodule.\n\nAnything else you want to add:\nI stay at your disposal if you need more information.\n\nPlease review the rest of the bug report below.\nYou can delete any lines you don't wish to share.\n\n\n[System Info]\ngit version:\ngit version 2.30.0.windows.1\ncpu: x86_64\nbuilt from commit: 18da6dbba950f8cc7b7d07057f7c30bf7cf207b6\nsizeof-long: 4\nsizeof-size_t: 8\nshell-path: /bin/sh\nuname: Windows 10.0 19041 \ncompiler info: gnuc: 10.2\nlibc info: no libc information available\n$SHELL (typically, interactive shell): C:\\Program Files\\Git\\usr\\bin\\bash.exe\n\n\n[Enabled Hooks]\n\nSincerely yours,\n\nKevin Bernard\n\n"},{"id":"414355","messageId":"05afbdeb-6c72-f14c-cdf0-e14894de05a3@gmail.com","threadId":"54986","inReplyTo":"570e77a07f0b4d4ea09307e5fa819d6f@fiveco.ch","subject":"Re: bug: checkout --recurse-submodules discard uncommited changes in submodule","fromName":"Philippe Blain","fromEmail":"levraiphilippeblain@gmail.com","sentAt":"2021-01-14T13:54:45Z","receivedAt":"2021-01-14T13:55:31Z","isPatch":false,"sender":{"key":"levraiphilippeblain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/44212482?v=4"},"body":"Hi Kevin,\n\nLe 2021-01-14 à 03:35, Kevin Bernard a écrit :\n> Thank you for filling out a Git bug report!\n> Please answer the following questions to help us understand your issue.\n> \n> What did you do before the bug happened? (Steps to reproduce your issue)\n> Make a git repository with a submodule in it.\n> Make two different commits in the main repository with two different versions of\n> the submodule, one of them is the head of the branch.\n> Checkout the head of the branch in the main repository, and make a submodule update.\n> Make a modification, do not commit it, in a submodule file that will not result\n> in a \"error: Your local changes to the following files would be overwritten by\n> checkout\" when the other version of the library will be checked out.\n\nI assume that you confirmed that by running 'git checkout <other version>'\nin the submodule, right ?\n\n> Go back to the main repository and make a checkout of the other commit with the\n> switch --recurse-submodules.\n> \n> What did you expect to happen? (Expected behavior)\n> The checkout with the switch --recurse-submodules should fail when there are\n> uncommitted changes in the submodule.\n> \n> What happened instead? (Actual behavior)\n> Uncommitted changes in the submodule are discarded without any notifications.\n> \n> What's different between what you expected and what actually happened?\n> Loss of the uncommitted changes in the submodule.\n> \n> Anything else you want to add:\n> I stay at your disposal if you need more information.\n\n\nThanks for the report. This is a known problem that was reported in [1] and [2].\nI'm currently working on fixing that bug. I'm not quite finished yet as I want\nto polish the end-user experience a bit, but if you want to compile from source,\nthe heart of the fix is this change:\n\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 323280dd48..a3e3d98de1 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1872,7 +1872,7 @@ static int verify_uptodate_1(const struct cache_entry *ce,\n  \n  \t\tif (submodule_from_ce(ce)) {\n  \t\t\tint r = check_submodule_move_head(ce,\n-\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid), o);\n+\t\t\t\t\"HEAD\", empty_tree_oid_hex(), o);\n  \t\t\tif (r)\n  \t\t\t\treturn add_rejected_path(o, error_type, ce->name);\n  \t\t\treturn 0;\n\n\nThis should disallow switching branches with '--recurse-submodules' if *any* file\nin the submodule is modified.\n\nHowever, I'm actually thinking that maybe it would\nbe better to let the checkout succeed in the exact case you mention, i.e. when\nthe modified files in the submodules are at the same version in both submodule\ncommits (i.e. git checkout <other version> in the submodule succeeds and the\nmodified files stay modified), and also carry over the modified files in the\nsubmodule. This would mimic the 'git checkout' experience\nwithout submodules, i.e. modified files that do not conflict are carried over\nto the branch you are checking out.\n\nIf you can write a complete reproducer (complete steps starting with 'git init',\netc.) I will make sure that your scenario is adequately tested in my patch series.\n\n\nCheers,\n\nPhilippe.\n\n\n[1] https://lore.kernel.org/git/CAHsG2VT4YB_nf8PrEmrHwK-iY-AQo0VDcvXGVsf8cEYXws4nig@mail.gmail.com/\n[2] https://lore.kernel.org/git/20200525094019.22padbzuk7ukr5uv@overdrive.tratt.net/\n"},{"id":"414360","messageId":"1ce5bfa2e8b04bf79b831515e096a9f1@fiveco.ch","threadId":"54986","inReplyTo":"05afbdeb-6c72-f14c-cdf0-e14894de05a3@gmail.com","subject":"RE: bug: checkout --recurse-submodules discard uncommited changes in submodule","fromName":"Kevin Bernard","fromEmail":"kevin.bernard@fiveco.ch","sentAt":"2021-01-14T16:40:28Z","receivedAt":"2021-01-14T16:41:20Z","isPatch":false,"sender":{"key":"kevin.bernard@fiveco.ch","avatar":null},"body":"Hi Philippe, \n\nI have no preferences whether the checkout should fail if any files are modified in the submodule\nor allow the checkout to succeed if the modification can be carried out. \n\nI wrote a step by step procedure to reproduce the bug.\n\nStep to reproduce my issue\n\ngit init  \ngit checkout -b master  \ngit submodule add https://github.com/kbernard-perso/recurse-bug.git  \ngit submodule init  \ngit add .  \ngit commit -m \"Add submodule\"  \ncd recurse-bug/  \necho \"file1 modified\" >> file1.txt  \ngit add .  \ngit commit -m \"file1.txt modified\"  \ncd ..  \ngit add .  \ngit commit -m \"Modified file1 in submodule\"  \ncd recurse-bug/  \necho \"file2 modified\" >> file2.txt  \ncd ..  \ngit status  \ngit checkout --recurse-submodules HEAD^  \ngit status  \n\nThe uncommitted modifications made with \"echo \"file2 modified\" >> file2.txt\" are  \ndiscarded by git checkout --recurse-submodules HEAD^  \n\nThank you very much for making git a wonderful tool to use.\n\nCheers, \n\nKevin\n\n-----Message d'origine-----\nDe : Philippe Blain <levraiphilippeblain@gmail.com> \nEnvoyé : jeudi, 14 janvier 2021 14:55\nÀ : Kevin Bernard <kevin.bernard@fiveco.ch>; git@vger.kernel.org\nObjet : Re: bug: checkout --recurse-submodules discard uncommited changes in submodule\n\nHi Kevin,\n\nLe 2021-01-14 à 03:35, Kevin Bernard a écrit :\n> Thank you for filling out a Git bug report!\n> Please answer the following questions to help us understand your issue.\n> \n> What did you do before the bug happened? (Steps to reproduce your \n> issue) Make a git repository with a submodule in it.\n> Make two different commits in the main repository with two different \n> versions of the submodule, one of them is the head of the branch.\n> Checkout the head of the branch in the main repository, and make a submodule update.\n> Make a modification, do not commit it, in a submodule file that will \n> not result in a \"error: Your local changes to the following files \n> would be overwritten by checkout\" when the other version of the library will be checked out.\n\nI assume that you confirmed that by running 'git checkout <other version>'\nin the submodule, right ?\n\n> Go back to the main repository and make a checkout of the other commit \n> with the switch --recurse-submodules.\n> \n> What did you expect to happen? (Expected behavior) The checkout with \n> the switch --recurse-submodules should fail when there are uncommitted \n> changes in the submodule.\n> \n> What happened instead? (Actual behavior) Uncommitted changes in the \n> submodule are discarded without any notifications.\n> \n> What's different between what you expected and what actually happened?\n> Loss of the uncommitted changes in the submodule.\n> \n> Anything else you want to add:\n> I stay at your disposal if you need more information.\n\n\nThanks for the report. This is a known problem that was reported in [1] and [2].\nI'm currently working on fixing that bug. I'm not quite finished yet as I want to polish the end-user experience a bit, but if you want to compile from source, the heart of the fix is this change:\n\ndiff --git a/unpack-trees.c b/unpack-trees.c index 323280dd48..a3e3d98de1 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1872,7 +1872,7 @@ static int verify_uptodate_1(const struct cache_entry *ce,\n  \n  \t\tif (submodule_from_ce(ce)) {\n  \t\t\tint r = check_submodule_move_head(ce,\n-\t\t\t\t\"HEAD\", oid_to_hex(&ce->oid), o);\n+\t\t\t\t\"HEAD\", empty_tree_oid_hex(), o);\n  \t\t\tif (r)\n  \t\t\t\treturn add_rejected_path(o, error_type, ce->name);\n  \t\t\treturn 0;\n\n\nThis should disallow switching branches with '--recurse-submodules' if *any* file in the submodule is modified.\n\nHowever, I'm actually thinking that maybe it would be better to let the checkout succeed in the exact case you mention, i.e. when the modified files in the submodules are at the same version in both submodule commits (i.e. git checkout <other version> in the submodule succeeds and the modified files stay modified), and also carry over the modified files in the submodule. This would mimic the 'git checkout' experience without submodules, i.e. modified files that do not conflict are carried over to the branch you are checking out.\n\nIf you can write a complete reproducer (complete steps starting with 'git init',\netc.) I will make sure that your scenario is adequately tested in my patch series.\n\n\nCheers,\n\nPhilippe.\n\n\n[1] https://lore.kernel.org/git/CAHsG2VT4YB_nf8PrEmrHwK-iY-AQo0VDcvXGVsf8cEYXws4nig@mail.gmail.com/\n[2] https://lore.kernel.org/git/20200525094019.22padbzuk7ukr5uv@overdrive.tratt.net/\n"}]}