add_cache_entry(): removal of file foo does not conflict with foo/bar
Similarly, removal of file foo/bar does not conflict with a file foo. Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
40
read-cache.c
40
read-cache.c
@ -487,6 +487,8 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac
|
|||||||
continue;
|
continue;
|
||||||
if (p->name[len] != '/')
|
if (p->name[len] != '/')
|
||||||
continue;
|
continue;
|
||||||
|
if (!ce_stage(p) && !p->ce_mode)
|
||||||
|
continue;
|
||||||
retval = -1;
|
retval = -1;
|
||||||
if (!ok_to_replace)
|
if (!ok_to_replace)
|
||||||
break;
|
break;
|
||||||
@ -519,26 +521,37 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
|||||||
|
|
||||||
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
|
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
|
||||||
if (pos >= 0) {
|
if (pos >= 0) {
|
||||||
retval = -1;
|
/*
|
||||||
if (!ok_to_replace)
|
* Found one, but not so fast. This could
|
||||||
break;
|
* be a marker that says "I was here, but
|
||||||
remove_cache_entry_at(pos);
|
* I am being removed". Such an entry is
|
||||||
continue;
|
* not a part of the resulting tree, and
|
||||||
|
* it is Ok to have a directory at the same
|
||||||
|
* path.
|
||||||
|
*/
|
||||||
|
if (stage || active_cache[pos]->ce_mode) {
|
||||||
|
retval = -1;
|
||||||
|
if (!ok_to_replace)
|
||||||
|
break;
|
||||||
|
remove_cache_entry_at(pos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
pos = -pos-1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trivial optimization: if we find an entry that
|
* Trivial optimization: if we find an entry that
|
||||||
* already matches the sub-directory, then we know
|
* already matches the sub-directory, then we know
|
||||||
* we're ok, and we can exit.
|
* we're ok, and we can exit.
|
||||||
*/
|
*/
|
||||||
pos = -pos-1;
|
|
||||||
while (pos < active_nr) {
|
while (pos < active_nr) {
|
||||||
struct cache_entry *p = active_cache[pos];
|
struct cache_entry *p = active_cache[pos];
|
||||||
if ((ce_namelen(p) <= len) ||
|
if ((ce_namelen(p) <= len) ||
|
||||||
(p->name[len] != '/') ||
|
(p->name[len] != '/') ||
|
||||||
memcmp(p->name, name, len))
|
memcmp(p->name, name, len))
|
||||||
break; /* not our subdirectory */
|
break; /* not our subdirectory */
|
||||||
if (ce_stage(p) == stage)
|
if (ce_stage(p) == stage && (stage || p->ce_mode))
|
||||||
/* p is at the same stage as our entry, and
|
/* p is at the same stage as our entry, and
|
||||||
* is a subdirectory of what we are looking
|
* is a subdirectory of what we are looking
|
||||||
* at, so we cannot have conflicts at our
|
* at, so we cannot have conflicts at our
|
||||||
@ -562,12 +575,21 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
|||||||
*/
|
*/
|
||||||
static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
|
static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
|
||||||
{
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When ce is an "I am going away" entry, we allow it to be added
|
||||||
|
*/
|
||||||
|
if (!ce_stage(ce) && !ce->ce_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We check if the path is a sub-path of a subsequent pathname
|
* We check if the path is a sub-path of a subsequent pathname
|
||||||
* first, since removing those will not change the position
|
* first, since removing those will not change the position
|
||||||
* in the array
|
* in the array.
|
||||||
*/
|
*/
|
||||||
int retval = has_file_name(ce, pos, ok_to_replace);
|
retval = has_file_name(ce, pos, ok_to_replace);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Then check if the path might have a clashing sub-directory
|
* Then check if the path might have a clashing sub-directory
|
||||||
* before it.
|
* before it.
|
||||||
|
Reference in New Issue
Block a user