unpack-trees: check if we can perform the operation for submodules

In a later patch we'll support submodule entries to be in sync with the tree in working tree changing commands, such as checkout or read-tree. When a new submodule entry changes in the tree, we need to check if there are conflicts (directory/file conflicts) for the tree. Add this check for submodules to be performed before the working tree is touched. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stefan Beller committed Mar 14, 2017 at 14:46 UTC a7bc845a9ae2bc4c58566e6744dd3cec0f805244
2 files changed +123 -9
unpack-trees.c
+122 -9
@@ -10,6 +10,8 @@
10 #include "attr.h"
11 #include "split-index.h"
12 #include "dir.h"
13 +#include "submodule.h"
14 +#include "submodule-config.h"
15
16 /*
17 * Error messages expected by scripts out of plumbing commands such as
@@ -45,6 +47,9 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
47
48 /* ERROR_WOULD_LOSE_ORPHANED_REMOVED */
49 "Working tree file '%s' would be removed by sparse checkout update.",
50 +
51 + /* ERROR_WOULD_LOSE_SUBMODULE */
52 + "Submodule '%s' cannot checkout new HEAD.",
53 };
54
55 #define ERRORMSG(o,type) \
@@ -161,6 +166,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
166 _("The following working tree files would be overwritten by sparse checkout update:\n%s");
167 msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
168 _("The following working tree files would be removed by sparse checkout update:\n%s");
169 + msgs[ERROR_WOULD_LOSE_SUBMODULE] =
170 + _("Submodule '%s' cannot checkout new HEAD");
171
172 opts->show_all_errors = 1;
173 /* rejected paths may not have a static buffer */
@@ -240,12 +247,75 @@ static void display_error_msgs(struct unpack_trees_options *o)
247 fprintf(stderr, _("Aborting\n"));
248 }
249
250 +static int check_submodule_move_head(const struct cache_entry *ce,
251 + const char *old_id,
252 + const char *new_id,
253 + struct unpack_trees_options *o)
254 +{
255 + const struct submodule *sub = submodule_from_ce(ce);
256 + if (!sub)
257 + return 0;
258 +
259 + switch (sub->update_strategy.type) {
260 + case SM_UPDATE_UNSPECIFIED:
261 + case SM_UPDATE_CHECKOUT:
262 + if (submodule_move_head(ce->name, old_id, new_id, SUBMODULE_MOVE_HEAD_DRY_RUN))
263 + return o->gently ? -1 :
264 + add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
265 + return 0;
266 + case SM_UPDATE_NONE:
267 + return 0;
268 + case SM_UPDATE_REBASE:
269 + case SM_UPDATE_MERGE:
270 + case SM_UPDATE_COMMAND:
271 + default:
272 + warning(_("submodule update strategy not supported for submodule '%s'"), ce->name);
273 + return -1;
274 + }
275 +}
276 +
277 +static void reload_gitmodules_file(struct index_state *index,
278 + struct checkout *state)
279 +{
280 + int i;
281 + for (i = 0; i < index->cache_nr; i++) {
282 + struct cache_entry *ce = index->cache[i];
283 + if (ce->ce_flags & CE_UPDATE) {
284 + int r = strcmp(ce->name, ".gitmodules");
285 + if (r < 0)
286 + continue;
287 + else if (r == 0) {
288 + submodule_free();
289 + checkout_entry(ce, state, NULL);
290 + gitmodules_config();
291 + git_config(submodule_config, NULL);
292 + } else
293 + break;
294 + }
295 + }
296 +}
297 +
298 /*
299 * Unlink the last component and schedule the leading directories for
300 * removal, such that empty directories get removed.
301 */
302 static void unlink_entry(const struct cache_entry *ce)
303 {
304 + const struct submodule *sub = submodule_from_ce(ce);
305 + if (sub) {
306 + switch (sub->update_strategy.type) {
307 + case SM_UPDATE_UNSPECIFIED:
308 + case SM_UPDATE_CHECKOUT:
309 + case SM_UPDATE_REBASE:
310 + case SM_UPDATE_MERGE:
311 + submodule_move_head(ce->name, "HEAD", NULL,
312 + SUBMODULE_MOVE_HEAD_FORCE);
313 + break;
314 + case SM_UPDATE_NONE:
315 + case SM_UPDATE_COMMAND:
316 + return; /* Do not touch the submodule. */
317 + }
318 + }
319 if (!check_leading_path(ce->name, ce_namelen(ce)))
320 return;
321 if (remove_or_warn(ce->ce_mode, ce->name))
@@ -301,6 +371,9 @@ static int check_updates(struct unpack_trees_options *o)
371 remove_marked_cache_entries(index);
372 remove_scheduled_dirs();
373
374 + if (should_update_submodules() && o->update && !o->dry_run)
375 + reload_gitmodules_file(index, &state);
376 +
377 for (i = 0; i < index->cache_nr; i++) {
378 struct cache_entry *ce = index->cache[i];
379
@@ -1358,17 +1431,26 @@ static int verify_uptodate_1(const struct cache_entry *ce,
1431 if (!lstat(ce->name, &st)) {
1432 int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;
1433 unsigned changed = ie_match_stat(o->src_index, ce, &st, flags);
1434 +
1435 + if (submodule_from_ce(ce)) {
1436 + int r = check_submodule_move_head(ce,
1437 + "HEAD", oid_to_hex(&ce->oid), o);
1438 + if (r)
1439 + return o->gently ? -1 :
1440 + add_rejected_path(o, error_type, ce->name);
1441 + return 0;
1442 + }
1443 +
1444 if (!changed)
1445 return 0;
1446 /*
1364 - * NEEDSWORK: the current default policy is to allow
1365 - * submodule to be out of sync wrt the superproject
1366 - * index. This needs to be tightened later for
1367 - * submodules that are marked to be automatically
1368 - * checked out.
1447 + * Historic default policy was to allow submodule to be out
1448 + * of sync wrt the superproject index. If the submodule was
1449 + * not considered interesting above, we don't care here.
1450 */
1451 if (S_ISGITLINK(ce->ce_mode))
1452 return 0;
1453 +
1454 errno = 0;
1455 }
1456 if (errno == ENOENT)
@@ -1412,7 +1494,11 @@ static int verify_clean_submodule(const char *old_sha1,
1494 enum unpack_trees_error_types error_type,
1495 struct unpack_trees_options *o)
1496 {
1415 - return 0;
1497 + if (!submodule_from_ce(ce))
1498 + return 0;
1499 +
1500 + return check_submodule_move_head(ce, old_sha1,
1501 + oid_to_hex(&ce->oid), o);
1502 }
1503
1504 static int verify_clean_subdirectory(const struct cache_entry *ce,
@@ -1578,9 +1664,15 @@ static int verify_absent_1(const struct cache_entry *ce,
1664 path = xmemdupz(ce->name, len);
1665 if (lstat(path, &st))
1666 ret = error_errno("cannot stat '%s'", path);
1581 - else
1582 - ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL,
1583 - &st, error_type, o);
1667 + else {
1668 + if (submodule_from_ce(ce))
1669 + ret = check_submodule_move_head(ce,
1670 + oid_to_hex(&ce->oid),
1671 + NULL, o);
1672 + else
1673 + ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL,
1674 + &st, error_type, o);
1675 + }
1676 free(path);
1677 return ret;
1678 } else if (lstat(ce->name, &st)) {
@@ -1588,6 +1680,10 @@ static int verify_absent_1(const struct cache_entry *ce,
1680 return error_errno("cannot stat '%s'", ce->name);
1681 return 0;
1682 } else {
1683 + if (submodule_from_ce(ce))
1684 + return check_submodule_move_head(ce, oid_to_hex(&ce->oid),
1685 + NULL, o);
1686 +
1687 return check_ok_to_remove(ce->name, ce_namelen(ce),
1688 ce_to_dtype(ce), ce, &st,
1689 error_type, o);
@@ -1643,6 +1739,15 @@ static int merged_entry(const struct cache_entry *ce,
1739 return -1;
1740 }
1741 invalidate_ce_path(merge, o);
1742 +
1743 + if (submodule_from_ce(ce)) {
1744 + int ret = check_submodule_move_head(ce, NULL,
1745 + oid_to_hex(&ce->oid),
1746 + o);
1747 + if (ret)
1748 + return ret;
1749 + }
1750 +
1751 } else if (!(old->ce_flags & CE_CONFLICTED)) {
1752 /*
1753 * See if we can re-use the old CE directly?
@@ -1663,6 +1768,14 @@ static int merged_entry(const struct cache_entry *ce,
1768 update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
1769 invalidate_ce_path(old, o);
1770 }
1771 +
1772 + if (submodule_from_ce(ce)) {
1773 + int ret = check_submodule_move_head(ce, oid_to_hex(&old->oid),
1774 + oid_to_hex(&ce->oid),
1775 + o);
1776 + if (ret)
1777 + return ret;
1778 + }
1779 } else {
1780 /*
1781 * Previously unmerged entry left as an existence
unpack-trees.h
+1
@@ -21,6 +21,7 @@ enum unpack_trees_error_types {
21 ERROR_SPARSE_NOT_UPTODATE_FILE,
22 ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN,
23 ERROR_WOULD_LOSE_ORPHANED_REMOVED,
24 + ERROR_WOULD_LOSE_SUBMODULE,
25 NB_UNPACK_TREES_ERROR_TYPES
26 };
27