Skip to content

Commit 640ee0d

Browse files
author
Junio C Hamano
committed
Merge branch 'jc/read-tree-df' (early part)
* 'jc/read-tree-df' (early part): Fix switching to a branch with D/F when current branch has file D. Fix twoway_merge that passed d/f conflict marker to merged_entry(). Fix read-tree --prefix=dir/. unpack-trees: get rid of *indpos parameter. unpack_trees.c: pass unpack_trees_options structure to keep_entry() as well. add_cache_entry(): removal of file foo does not conflict with foo/bar
2 parents 5838dff + c819353 commit 640ee0d

File tree

4 files changed

+167
-28
lines changed

4 files changed

+167
-28
lines changed

builtin-read-tree.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
233233
if (0 <= pos)
234234
die("file '%.*s' already exists.",
235235
pfxlen-1, opts.prefix);
236+
opts.pos = -1 - pos;
236237
}
237238

238239
if (opts.merge) {

read-cache.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,8 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac
485485
continue;
486486
if (p->name[len] != '/')
487487
continue;
488+
if (!ce_stage(p) && !p->ce_mode)
489+
continue;
488490
retval = -1;
489491
if (!ok_to_replace)
490492
break;
@@ -517,26 +519,37 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
517519

518520
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
519521
if (pos >= 0) {
520-
retval = -1;
521-
if (!ok_to_replace)
522-
break;
523-
remove_cache_entry_at(pos);
524-
continue;
522+
/*
523+
* Found one, but not so fast. This could
524+
* be a marker that says "I was here, but
525+
* I am being removed". Such an entry is
526+
* not a part of the resulting tree, and
527+
* it is Ok to have a directory at the same
528+
* path.
529+
*/
530+
if (stage || active_cache[pos]->ce_mode) {
531+
retval = -1;
532+
if (!ok_to_replace)
533+
break;
534+
remove_cache_entry_at(pos);
535+
continue;
536+
}
525537
}
538+
else
539+
pos = -pos-1;
526540

527541
/*
528542
* Trivial optimization: if we find an entry that
529543
* already matches the sub-directory, then we know
530544
* we're ok, and we can exit.
531545
*/
532-
pos = -pos-1;
533546
while (pos < active_nr) {
534547
struct cache_entry *p = active_cache[pos];
535548
if ((ce_namelen(p) <= len) ||
536549
(p->name[len] != '/') ||
537550
memcmp(p->name, name, len))
538551
break; /* not our subdirectory */
539-
if (ce_stage(p) == stage)
552+
if (ce_stage(p) == stage && (stage || p->ce_mode))
540553
/* p is at the same stage as our entry, and
541554
* is a subdirectory of what we are looking
542555
* at, so we cannot have conflicts at our
@@ -560,12 +573,21 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
560573
*/
561574
static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
562575
{
576+
int retval;
577+
578+
/*
579+
* When ce is an "I am going away" entry, we allow it to be added
580+
*/
581+
if (!ce_stage(ce) && !ce->ce_mode)
582+
return 0;
583+
563584
/*
564585
* We check if the path is a sub-path of a subsequent pathname
565586
* first, since removing those will not change the position
566-
* in the array
587+
* in the array.
567588
*/
568-
int retval = has_file_name(ce, pos, ok_to_replace);
589+
retval = has_file_name(ce, pos, ok_to_replace);
590+
569591
/*
570592
* Then check if the path might have a clashing sub-directory
571593
* before it.

unpack-trees.c

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ static int entcmp(const char *name1, int dir1, const char *name2, int dir2)
7070

7171
static int unpack_trees_rec(struct tree_entry_list **posns, int len,
7272
const char *base, struct unpack_trees_options *o,
73-
int *indpos,
7473
struct tree_entry_list *df_conflict_list)
7574
{
7675
int baselen = strlen(base);
@@ -100,7 +99,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
10099
cache_name = NULL;
101100

102101
/* Check the cache */
103-
if (o->merge && *indpos < active_nr) {
102+
if (o->merge && o->pos < active_nr) {
104103
/* This is a bit tricky: */
105104
/* If the index has a subdirectory (with
106105
* contents) as the first name, it'll get a
@@ -118,7 +117,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
118117
* file case.
119118
*/
120119

121-
cache_name = active_cache[*indpos]->name;
120+
cache_name = active_cache[o->pos]->name;
122121
if (strlen(cache_name) > baselen &&
123122
!memcmp(cache_name, base, baselen)) {
124123
cache_name += baselen;
@@ -158,8 +157,8 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
158157

159158
if (cache_name && !strcmp(cache_name, first)) {
160159
any_files = 1;
161-
src[0] = active_cache[*indpos];
162-
remove_cache_entry_at(*indpos);
160+
src[0] = active_cache[o->pos];
161+
remove_cache_entry_at(o->pos);
163162
}
164163

165164
for (i = 0; i < len; i++) {
@@ -228,7 +227,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
228227
#if DBRT_DEBUG > 1
229228
printf("Added %d entries\n", ret);
230229
#endif
231-
*indpos += ret;
230+
o->pos += ret;
232231
} else {
233232
for (i = 0; i < src_size; i++) {
234233
if (src[i]) {
@@ -244,7 +243,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
244243
newbase[baselen + pathlen] = '/';
245244
newbase[baselen + pathlen + 1] = '\0';
246245
if (unpack_trees_rec(subposns, len, newbase, o,
247-
indpos, df_conflict_list)) {
246+
df_conflict_list)) {
248247
retval = -1;
249248
goto leave_directory;
250249
}
@@ -375,7 +374,6 @@ static void check_updates(struct cache_entry **src, int nr,
375374

376375
int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
377376
{
378-
int indpos = 0;
379377
unsigned len = object_list_length(trees);
380378
struct tree_entry_list **posns;
381379
int i;
@@ -404,7 +402,7 @@ int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
404402
posn = posn->next;
405403
}
406404
if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
407-
o, &indpos, &df_conflict_list))
405+
o, &df_conflict_list))
408406
return -1;
409407
}
410408

@@ -467,6 +465,64 @@ static void invalidate_ce_path(struct cache_entry *ce)
467465
cache_tree_invalidate_path(active_cache_tree, ce->name);
468466
}
469467

468+
static int verify_clean_subdirectory(const char *path, const char *action,
469+
struct unpack_trees_options *o)
470+
{
471+
/*
472+
* we are about to extract "path"; we would not want to lose
473+
* anything in the existing directory there.
474+
*/
475+
int namelen;
476+
int pos, i;
477+
struct dir_struct d;
478+
char *pathbuf;
479+
int cnt = 0;
480+
481+
/*
482+
* First let's make sure we do not have a local modification
483+
* in that directory.
484+
*/
485+
namelen = strlen(path);
486+
pos = cache_name_pos(path, namelen);
487+
if (0 <= pos)
488+
return cnt; /* we have it as nondirectory */
489+
pos = -pos - 1;
490+
for (i = pos; i < active_nr; i++) {
491+
struct cache_entry *ce = active_cache[i];
492+
int len = ce_namelen(ce);
493+
if (len < namelen ||
494+
strncmp(path, ce->name, namelen) ||
495+
ce->name[namelen] != '/')
496+
break;
497+
/*
498+
* ce->name is an entry in the subdirectory.
499+
*/
500+
if (!ce_stage(ce)) {
501+
verify_uptodate(ce, o);
502+
ce->ce_mode = 0;
503+
}
504+
cnt++;
505+
}
506+
507+
/*
508+
* Then we need to make sure that we do not lose a locally
509+
* present file that is not ignored.
510+
*/
511+
pathbuf = xmalloc(namelen + 2);
512+
memcpy(pathbuf, path, namelen);
513+
strcpy(pathbuf+namelen, "/");
514+
515+
memset(&d, 0, sizeof(d));
516+
if (o->dir)
517+
d.exclude_per_dir = o->dir->exclude_per_dir;
518+
i = read_directory(&d, path, pathbuf, namelen+1, NULL);
519+
if (i)
520+
die("Updating '%s' would lose untracked files in it",
521+
path);
522+
free(pathbuf);
523+
return cnt;
524+
}
525+
470526
/*
471527
* We do not want to remove or overwrite a working tree file that
472528
* is not tracked, unless it is ignored.
@@ -478,9 +534,62 @@ static void verify_absent(const char *path, const char *action,
478534

479535
if (o->index_only || o->reset || !o->update)
480536
return;
481-
if (!lstat(path, &st) && !(o->dir && excluded(o->dir, path)))
537+
538+
if (!lstat(path, &st)) {
539+
int cnt;
540+
541+
if (o->dir && excluded(o->dir, path))
542+
/*
543+
* path is explicitly excluded, so it is Ok to
544+
* overwrite it.
545+
*/
546+
return;
547+
if (S_ISDIR(st.st_mode)) {
548+
/*
549+
* We are checking out path "foo" and
550+
* found "foo/." in the working tree.
551+
* This is tricky -- if we have modified
552+
* files that are in "foo/" we would lose
553+
* it.
554+
*/
555+
cnt = verify_clean_subdirectory(path, action, o);
556+
557+
/*
558+
* If this removed entries from the index,
559+
* what that means is:
560+
*
561+
* (1) the caller unpack_trees_rec() saw path/foo
562+
* in the index, and it has not removed it because
563+
* it thinks it is handling 'path' as blob with
564+
* D/F conflict;
565+
* (2) we will return "ok, we placed a merged entry
566+
* in the index" which would cause o->pos to be
567+
* incremented by one;
568+
* (3) however, original o->pos now has 'path/foo'
569+
* marked with "to be removed".
570+
*
571+
* We need to increment it by the number of
572+
* deleted entries here.
573+
*/
574+
o->pos += cnt;
575+
return;
576+
}
577+
578+
/*
579+
* The previous round may already have decided to
580+
* delete this path, which is in a subdirectory that
581+
* is being replaced with a blob.
582+
*/
583+
cnt = cache_name_pos(path, strlen(path));
584+
if (0 <= cnt) {
585+
struct cache_entry *ce = active_cache[cnt];
586+
if (!ce_stage(ce) && !ce->ce_mode)
587+
return;
588+
}
589+
482590
die("Untracked working tree file '%s' "
483591
"would be %s by merge.", path, action);
592+
}
484593
}
485594

486595
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
@@ -525,7 +634,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
525634
return 1;
526635
}
527636

528-
static int keep_entry(struct cache_entry *ce)
637+
static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
529638
{
530639
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
531640
return 1;
@@ -682,7 +791,7 @@ int threeway_merge(struct cache_entry **stages,
682791
if (!head_match || !remote_match) {
683792
for (i = 1; i < o->head_idx; i++) {
684793
if (stages[i]) {
685-
keep_entry(stages[i]);
794+
keep_entry(stages[i], o);
686795
count++;
687796
break;
688797
}
@@ -695,8 +804,8 @@ int threeway_merge(struct cache_entry **stages,
695804
show_stage_entry(stderr, "remote ", stages[remote_match]);
696805
}
697806
#endif
698-
if (head) { count += keep_entry(head); }
699-
if (remote) { count += keep_entry(remote); }
807+
if (head) { count += keep_entry(head, o); }
808+
if (remote) { count += keep_entry(remote, o); }
700809
return count;
701810
}
702811

@@ -713,22 +822,28 @@ int twoway_merge(struct cache_entry **src,
713822
struct unpack_trees_options *o)
714823
{
715824
struct cache_entry *current = src[0];
716-
struct cache_entry *oldtree = src[1], *newtree = src[2];
825+
struct cache_entry *oldtree = src[1];
826+
struct cache_entry *newtree = src[2];
717827

718828
if (o->merge_size != 2)
719829
return error("Cannot do a twoway merge of %d trees",
720830
o->merge_size);
721831

832+
if (oldtree == o->df_conflict_entry)
833+
oldtree = NULL;
834+
if (newtree == o->df_conflict_entry)
835+
newtree = NULL;
836+
722837
if (current) {
723838
if ((!oldtree && !newtree) || /* 4 and 5 */
724839
(!oldtree && newtree &&
725840
same(current, newtree)) || /* 6 and 7 */
726841
(oldtree && newtree &&
727842
same(oldtree, newtree)) || /* 14 and 15 */
728843
(oldtree && newtree &&
729-
!same(oldtree, newtree) && /* 18 and 19*/
844+
!same(oldtree, newtree) && /* 18 and 19 */
730845
same(current, newtree))) {
731-
return keep_entry(current);
846+
return keep_entry(current, o);
732847
}
733848
else if (oldtree && !newtree && same(current, oldtree)) {
734849
/* 10 or 11 */
@@ -774,7 +889,7 @@ int bind_merge(struct cache_entry **src,
774889
if (a && old)
775890
die("Entry '%s' overlaps. Cannot bind.", a->name);
776891
if (!a)
777-
return keep_entry(old);
892+
return keep_entry(old, o);
778893
else
779894
return merged_entry(a, NULL, o);
780895
}
@@ -804,7 +919,7 @@ int oneway_merge(struct cache_entry **src,
804919
ce_match_stat(old, &st, 1))
805920
old->ce_flags |= htons(CE_UPDATE);
806921
}
807-
return keep_entry(old);
922+
return keep_entry(old, o);
808923
}
809924
return merged_entry(a, old, o);
810925
}

unpack-trees.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct unpack_trees_options {
1616
int verbose_update;
1717
int aggressive;
1818
const char *prefix;
19+
int pos;
1920
struct dir_struct *dir;
2021
merge_fn_t fn;
2122

0 commit comments

Comments
 (0)