Skip to content

Commit 00a6d4d

Browse files
pcloudsgitster
authored andcommitted
worktree: allow to (re)move worktrees with uninitialized submodules
Uninitialized submodules have nothing valueable for us to be worried about. They are just SHA-1. Let "worktree remove" and "worktree move" continue in this case so that people can still use multiple worktrees on repos with optional submodules that are never populated, like sha1collisiondetection in git.git when checked out by doc-diff script. Note that for "worktree remove", it is possible that a user initializes a submodule (*), makes some commits (but not push), then deinitializes it. At that point, the submodule is unpopulated, but the precious new commits are still in $GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule> directory and we should not allow removing the worktree or we lose those commits forever. The new directory check is added to prevent this. (*) yes they are screwed anyway by doing this since "git submodule" would add submodule.* in $GIT_COMMON_DIR/config, which is shared across multiple worktrees. But it does not mean we let them be screwed even more. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b21ebb6 commit 00a6d4d

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

builtin/worktree.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "refs.h"
1010
#include "run-command.h"
1111
#include "sigchain.h"
12+
#include "submodule.h"
1213
#include "refs.h"
1314
#include "utf8.h"
1415
#include "worktree.h"
@@ -724,20 +725,36 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
724725
static void validate_no_submodules(const struct worktree *wt)
725726
{
726727
struct index_state istate = { NULL };
728+
struct strbuf path = STRBUF_INIT;
727729
int i, found_submodules = 0;
728730

729-
if (read_index_from(&istate, worktree_git_path(wt, "index"),
730-
get_worktree_git_dir(wt)) > 0) {
731+
if (is_directory(worktree_git_path(wt, "modules"))) {
732+
/*
733+
* There could be false positives, e.g. the "modules"
734+
* directory exists but is empty. But it's a rare case and
735+
* this simpler check is probably good enough for now.
736+
*/
737+
found_submodules = 1;
738+
} else if (read_index_from(&istate, worktree_git_path(wt, "index"),
739+
get_worktree_git_dir(wt)) > 0) {
731740
for (i = 0; i < istate.cache_nr; i++) {
732741
struct cache_entry *ce = istate.cache[i];
742+
int err;
733743

734-
if (S_ISGITLINK(ce->ce_mode)) {
735-
found_submodules = 1;
736-
break;
737-
}
744+
if (!S_ISGITLINK(ce->ce_mode))
745+
continue;
746+
747+
strbuf_reset(&path);
748+
strbuf_addf(&path, "%s/%s", wt->path, ce->name);
749+
if (!is_submodule_populated_gently(path.buf, &err))
750+
continue;
751+
752+
found_submodules = 1;
753+
break;
738754
}
739755
}
740756
discard_index(&istate);
757+
strbuf_release(&path);
741758

742759
if (found_submodules)
743760
die(_("working trees containing submodules cannot be moved or removed"));

t/t2028-worktree-move.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,26 @@ test_expect_success 'move locked worktree (force)' '
112112
git worktree move --force --force flump ploof
113113
'
114114

115+
test_expect_success 'move a repo with uninitialized submodule' '
116+
git init withsub &&
117+
(
118+
cd withsub &&
119+
test_commit initial &&
120+
git submodule add "$PWD"/.git sub &&
121+
git commit -m withsub &&
122+
git worktree add second HEAD &&
123+
git worktree move second third
124+
)
125+
'
126+
127+
test_expect_success 'not move a repo with initialized submodule' '
128+
(
129+
cd withsub &&
130+
git -C third submodule update &&
131+
test_must_fail git worktree move third forth
132+
)
133+
'
134+
115135
test_expect_success 'remove main worktree' '
116136
test_must_fail git worktree remove .
117137
'
@@ -185,4 +205,21 @@ test_expect_success 'remove cleans up .git/worktrees when empty' '
185205
)
186206
'
187207

208+
test_expect_success 'remove a repo with uninitialized submodule' '
209+
(
210+
cd withsub &&
211+
git worktree add to-remove HEAD &&
212+
git worktree remove to-remove
213+
)
214+
'
215+
216+
test_expect_success 'not remove a repo with initialized submodule' '
217+
(
218+
cd withsub &&
219+
git worktree add to-remove HEAD &&
220+
git -C to-remove submodule update &&
221+
test_must_fail git worktree remove to-remove
222+
)
223+
'
224+
188225
test_done

0 commit comments

Comments
 (0)