Skip to content

Commit a7bc845

Browse files
stefanbellergitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d6b1230 commit a7bc845

File tree

2 files changed

+123
-9
lines changed

2 files changed

+123
-9
lines changed

unpack-trees.c

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "attr.h"
1111
#include "split-index.h"
1212
#include "dir.h"
13+
#include "submodule.h"
14+
#include "submodule-config.h"
1315

1416
/*
1517
* 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] = {
4547

4648
/* ERROR_WOULD_LOSE_ORPHANED_REMOVED */
4749
"Working tree file '%s' would be removed by sparse checkout update.",
50+
51+
/* ERROR_WOULD_LOSE_SUBMODULE */
52+
"Submodule '%s' cannot checkout new HEAD.",
4853
};
4954

5055
#define ERRORMSG(o,type) \
@@ -161,6 +166,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
161166
_("The following working tree files would be overwritten by sparse checkout update:\n%s");
162167
msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
163168
_("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");
164171

165172
opts->show_all_errors = 1;
166173
/* rejected paths may not have a static buffer */
@@ -240,12 +247,75 @@ static void display_error_msgs(struct unpack_trees_options *o)
240247
fprintf(stderr, _("Aborting\n"));
241248
}
242249

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+
243298
/*
244299
* Unlink the last component and schedule the leading directories for
245300
* removal, such that empty directories get removed.
246301
*/
247302
static void unlink_entry(const struct cache_entry *ce)
248303
{
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+
}
249319
if (!check_leading_path(ce->name, ce_namelen(ce)))
250320
return;
251321
if (remove_or_warn(ce->ce_mode, ce->name))
@@ -301,6 +371,9 @@ static int check_updates(struct unpack_trees_options *o)
301371
remove_marked_cache_entries(index);
302372
remove_scheduled_dirs();
303373

374+
if (should_update_submodules() && o->update && !o->dry_run)
375+
reload_gitmodules_file(index, &state);
376+
304377
for (i = 0; i < index->cache_nr; i++) {
305378
struct cache_entry *ce = index->cache[i];
306379

@@ -1358,17 +1431,26 @@ static int verify_uptodate_1(const struct cache_entry *ce,
13581431
if (!lstat(ce->name, &st)) {
13591432
int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;
13601433
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+
13611444
if (!changed)
13621445
return 0;
13631446
/*
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.
13691450
*/
13701451
if (S_ISGITLINK(ce->ce_mode))
13711452
return 0;
1453+
13721454
errno = 0;
13731455
}
13741456
if (errno == ENOENT)
@@ -1412,7 +1494,11 @@ static int verify_clean_submodule(const char *old_sha1,
14121494
enum unpack_trees_error_types error_type,
14131495
struct unpack_trees_options *o)
14141496
{
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);
14161502
}
14171503

14181504
static int verify_clean_subdirectory(const struct cache_entry *ce,
@@ -1578,16 +1664,26 @@ static int verify_absent_1(const struct cache_entry *ce,
15781664
path = xmemdupz(ce->name, len);
15791665
if (lstat(path, &st))
15801666
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+
}
15841676
free(path);
15851677
return ret;
15861678
} else if (lstat(ce->name, &st)) {
15871679
if (errno != ENOENT)
15881680
return error_errno("cannot stat '%s'", ce->name);
15891681
return 0;
15901682
} else {
1683+
if (submodule_from_ce(ce))
1684+
return check_submodule_move_head(ce, oid_to_hex(&ce->oid),
1685+
NULL, o);
1686+
15911687
return check_ok_to_remove(ce->name, ce_namelen(ce),
15921688
ce_to_dtype(ce), ce, &st,
15931689
error_type, o);
@@ -1643,6 +1739,15 @@ static int merged_entry(const struct cache_entry *ce,
16431739
return -1;
16441740
}
16451741
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+
16461751
} else if (!(old->ce_flags & CE_CONFLICTED)) {
16471752
/*
16481753
* See if we can re-use the old CE directly?
@@ -1663,6 +1768,14 @@ static int merged_entry(const struct cache_entry *ce,
16631768
update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
16641769
invalidate_ce_path(old, o);
16651770
}
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+
}
16661779
} else {
16671780
/*
16681781
* Previously unmerged entry left as an existence

unpack-trees.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum unpack_trees_error_types {
2121
ERROR_SPARSE_NOT_UPTODATE_FILE,
2222
ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN,
2323
ERROR_WOULD_LOSE_ORPHANED_REMOVED,
24+
ERROR_WOULD_LOSE_SUBMODULE,
2425
NB_UNPACK_TREES_ERROR_TYPES
2526
};
2627

0 commit comments

Comments
 (0)