detect and ignore Git submodules
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
diff --git a/got/got.1 b/got/got.1
index 45c8c5c..ffc4d07 100644
--- a/got/got.1
+++ b/got/got.1
@@ -405,6 +405,7 @@ annotations:
.It @ Ta entry is a symbolic link
.It / Ta entry is a directory
.It * Ta entry is an executable file
+.It $ Ta entry is a Git submodule
.El
.Pp
If no
diff --git a/got/got.c b/got/got.c
index 34e0719..77942a8 100644
--- a/got/got.c
+++ b/got/got.c
@@ -2511,7 +2511,9 @@ print_entry(struct got_tree_entry *te, const char *id, const char *path,
while (path[0] == '/')
path++;
- if (S_ISLNK(te->mode))
+ if (got_object_tree_entry_is_submodule(te))
+ modestr = "$";
+ else if (S_ISLNK(te->mode))
modestr = "@";
else if (S_ISDIR(te->mode))
modestr = "/";
diff --git a/include/got_object.h b/include/got_object.h
index 93db9af..8063afe 100644
--- a/include/got_object.h
+++ b/include/got_object.h
@@ -186,6 +186,9 @@ const struct got_tree_entries *got_object_tree_get_entries(
const struct got_tree_entry *got_object_tree_find_entry(
struct got_tree_object *, const char *);
+/* Return non-zero if the specified tree entry is a Git submodule. */
+int got_object_tree_entry_is_submodule(const struct got_tree_entry *);
+
/*
* Compare two trees and indicate whether the entry at the specified path
* differs between them. The path must not be the root path "/"; the function
diff --git a/lib/diff.c b/lib/diff.c
index 3c3c339..e269983 100644
--- a/lib/diff.c
+++ b/lib/diff.c
@@ -498,6 +498,9 @@ diff_entry_old_new(const struct got_tree_entry *te1,
const struct got_error *err = NULL;
int id_match;
+ if (got_object_tree_entry_is_submodule(te1))
+ return NULL;
+
if (te2 == NULL) {
if (S_ISDIR(te1->mode))
err = diff_deleted_tree(te1->id, label1, repo,
@@ -511,7 +514,8 @@ diff_entry_old_new(const struct got_tree_entry *te1,
label1, NULL, repo);
}
return err;
- }
+ } else if (got_object_tree_entry_is_submodule(te2))
+ return NULL;
id_match = (got_object_id_cmp(te1->id, te2->id) == 0);
if (S_ISDIR(te1->mode) && S_ISDIR(te2->mode)) {
@@ -545,6 +549,9 @@ diff_entry_new_old(const struct got_tree_entry *te2,
if (te1 != NULL) /* handled by diff_entry_old_new() */
return NULL;
+ if (got_object_tree_entry_is_submodule(te2))
+ return NULL;
+
if (S_ISDIR(te2->mode))
return diff_added_tree(te2->id, label2, repo, cb, cb_arg,
diff_content);
diff --git a/lib/fileindex.c b/lib/fileindex.c
index 1f0d5de..696ab23 100644
--- a/lib/fileindex.c
+++ b/lib/fileindex.c
@@ -704,7 +704,7 @@ walk_tree(struct got_tree_entry **next, struct got_fileindex *fileindex,
{
const struct got_error *err = NULL;
- if (S_ISDIR(te->mode)) {
+ if (!got_object_tree_entry_is_submodule(te) && S_ISDIR(te->mode)) {
char *subpath;
struct got_tree_object *subtree;
@@ -756,7 +756,9 @@ diff_fileindex_tree(struct got_fileindex *fileindex,
free(te_path);
if (cmp == 0) {
if (got_path_is_child((*ie)->path, path,
- path_len) && (entry_name == NULL ||
+ path_len) &&
+ !got_object_tree_entry_is_submodule(te) &&
+ (entry_name == NULL ||
strcmp(te->name, entry_name) == 0)) {
err = cb->diff_old_new(cb_arg, *ie, te,
path);
@@ -799,8 +801,9 @@ diff_fileindex_tree(struct got_fileindex *fileindex,
}
*ie = next;
} else if (te) {
- if (entry_name == NULL ||
- strcmp(te->name, entry_name) == 0) {
+ if (!got_object_tree_entry_is_submodule(te) &&
+ (entry_name == NULL ||
+ strcmp(te->name, entry_name) == 0)) {
err = cb->diff_new(cb_arg, te, path);
if (err || entry_name)
break;
diff --git a/lib/object.c b/lib/object.c
index 72be8b6..e5c043c 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -1677,3 +1677,9 @@ done:
}
return err;
}
+
+int
+got_object_tree_entry_is_submodule(const struct got_tree_entry *te)
+{
+ return (te->mode & S_IFMT) == (S_IFDIR | S_IFLNK);
+}
diff --git a/lib/worktree.c b/lib/worktree.c
index 9a7c693..8921d44 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -1426,6 +1426,9 @@ diff_new(void *arg, struct got_tree_entry *te, const char *parent_path)
if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
return got_error(GOT_ERR_CANCELLED);
+ if (got_object_tree_entry_is_submodule(te))
+ return NULL;
+
if (asprintf(&path, "%s%s%s", parent_path,
parent_path[0] ? "/" : "", te->name)
== -1)
@@ -3835,6 +3838,17 @@ write_tree(struct got_object_id **new_tree_id,
SIMPLEQ_FOREACH(te, &base_entries->head, entry) {
struct got_commitable *ct = NULL;
+ if (got_object_tree_entry_is_submodule(te)) {
+ /* Entry is a submodule; just copy it. */
+ err = got_object_tree_entry_dup(&new_te, te);
+ if (err)
+ goto done;
+ err = insert_tree_entry(new_te, &paths);
+ if (err)
+ goto done;
+ continue;
+ }
+
if (S_ISDIR(te->mode)) {
int modified;
err = got_object_tree_entry_dup(&new_te, te);
diff --git a/regress/cmdline/checkout.sh b/regress/cmdline/checkout.sh
index b967040..76ad000 100755
--- a/regress/cmdline/checkout.sh
+++ b/regress/cmdline/checkout.sh
@@ -252,9 +252,54 @@ function test_checkout_tag {
test_done "$testroot" "$ret"
}
+function test_checkout_ignores_submodules {
+ local testroot=`test_init checkout_ignores_submodules`
+
+ (cd $testroot && git clone -q repo repo2 >/dev/null)
+ (cd $testroot/repo && git submodule -q add ../repo2)
+ (cd $testroot/repo && git commit -q -m 'adding submodule')
+
+ echo "A $testroot/wt/.gitmodules" > $testroot/stdout.expected
+ echo "A $testroot/wt/alpha" >> $testroot/stdout.expected
+ echo "A $testroot/wt/beta" >> $testroot/stdout.expected
+ echo "A $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected
+ echo "A $testroot/wt/gamma/delta" >> $testroot/stdout.expected
+ echo "Now shut up and hack" >> $testroot/stdout.expected
+
+ got checkout $testroot/repo $testroot/wt > $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "alpha" > $testroot/content.expected
+ echo "beta" >> $testroot/content.expected
+ echo "zeta" >> $testroot/content.expected
+ echo "delta" >> $testroot/content.expected
+ cat $testroot/wt/alpha $testroot/wt/beta $testroot/wt/epsilon/zeta \
+ $testroot/wt/gamma/delta > $testroot/content
+
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_checkout_basic
run_test test_checkout_dir_exists
run_test test_checkout_dir_not_empty
run_test test_checkout_sets_xbit
run_test test_checkout_commit_from_wrong_branch
run_test test_checkout_tag
+run_test test_checkout_ignores_submodules
diff --git a/tog/tog.1 b/tog/tog.1
index 46ebc3a..4af5ca7 100644
--- a/tog/tog.1
+++ b/tog/tog.1
@@ -247,6 +247,7 @@ Displayed tree entries may carry one of the following trailing annotations:
.It @ Ta entry is a symbolic link
.It / Ta entry is a directory
.It * Ta entry is an executable file
+.It $ Ta entry is a Git submodule
.El
.Pp
The key bindings for
diff --git a/tog/tog.c b/tog/tog.c
index d5a10ac..fbc6df4 100644
--- a/tog/tog.c
+++ b/tog/tog.c
@@ -3935,7 +3935,9 @@ draw_tree_entries(struct tog_view *view,
return got_error_from_errno(
"got_object_id_str");
}
- if (S_ISLNK(te->mode))
+ if (got_object_tree_entry_is_submodule(te))
+ modestr = "$";
+ else if (S_ISLNK(te->mode))
modestr = "@";
else if (S_ISDIR(te->mode))
modestr = "/";