Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'unpack-trees.c')
-rw-r--r--unpack-trees.c105
1 files changed, 49 insertions, 56 deletions
diff --git a/unpack-trees.c b/unpack-trees.c
index 5b0a8c1728..86e28650b8 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -52,36 +52,17 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
}
-/* Unlink the last component and attempt to remove leading
- * directories, in case this unlink is the removal of the
- * last entry in the directory -- empty directories are removed.
+/*
+ * Unlink the last component and schedule the leading directories for
+ * removal, such that empty directories get removed.
*/
static void unlink_entry(struct cache_entry *ce)
{
- char *cp, *prev;
- char *name = ce->name;
-
- if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+ if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
return;
- if (unlink(name))
+ if (unlink(ce->name))
return;
- prev = NULL;
- while (1) {
- int status;
- cp = strrchr(name, '/');
- if (prev)
- *prev = '/';
- if (!cp)
- break;
-
- *cp = 0;
- status = rmdir(name);
- if (status) {
- *cp = '/';
- break;
- }
- prev = cp;
- }
+ schedule_dir_for_removal(ce->name, ce_namelen(ce));
}
static struct checkout state;
@@ -112,11 +93,10 @@ static int check_updates(struct unpack_trees_options *o)
display_progress(progress, ++cnt);
if (o->update)
unlink_entry(ce);
- remove_index_entry_at(&o->result, i);
- i--;
- continue;
}
}
+ remove_marked_cache_entries(&o->result);
+ remove_scheduled_dirs();
for (i = 0; i < index->cache_nr; i++) {
struct cache_entry *ce = index->cache[i];
@@ -240,8 +220,11 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con
return ce;
}
-static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmask, struct cache_entry *src[5],
- const struct name_entry *names, const struct traverse_info *info)
+static int unpack_nondirectories(int n, unsigned long mask,
+ unsigned long dirmask,
+ struct cache_entry **src,
+ const struct name_entry *names,
+ const struct traverse_info *info)
{
int i;
struct unpack_trees_options *o = info->data;
@@ -291,7 +274,7 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas
static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *names, struct traverse_info *info)
{
- struct cache_entry *src[5] = { NULL, };
+ struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
struct unpack_trees_options *o = info->data;
const struct name_entry *p = names;
@@ -352,7 +335,7 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)
discard_index(&o->result);
if (!o->gently) {
if (message)
- return error(message);
+ return error("%s", message);
return -1;
}
return -1;
@@ -376,12 +359,15 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
state.refresh_cache = 1;
memset(&o->result, 0, sizeof(o->result));
- if (o->src_index)
- o->result.timestamp = o->src_index->timestamp;
+ o->result.initialized = 1;
+ if (o->src_index) {
+ o->result.timestamp.sec = o->src_index->timestamp.sec;
+ o->result.timestamp.nsec = o->src_index->timestamp.nsec;
+ }
o->merge_size = len;
if (!dfc)
- dfc = xcalloc(1, sizeof(struct cache_entry) + 1);
+ dfc = xcalloc(1, cache_entry_size(0));
o->df_conflict_entry = dfc;
if (len) {
@@ -442,7 +428,7 @@ static int verify_uptodate(struct cache_entry *ce,
{
struct stat st;
- if (o->index_only || o->reset)
+ if (o->index_only || o->reset || ce_uptodate(ce))
return 0;
if (!lstat(ce->name, &st)) {
@@ -493,7 +479,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
* anything in the existing directory there.
*/
int namelen;
- int pos, i;
+ int i;
struct dir_struct d;
char *pathbuf;
int cnt = 0;
@@ -514,24 +500,20 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
* in that directory.
*/
namelen = strlen(ce->name);
- pos = index_name_pos(o->src_index, ce->name, namelen);
- if (0 <= pos)
- return cnt; /* we have it as nondirectory */
- pos = -pos - 1;
- for (i = pos; i < o->src_index->cache_nr; i++) {
- struct cache_entry *ce = o->src_index->cache[i];
- int len = ce_namelen(ce);
+ for (i = o->pos; i < o->src_index->cache_nr; i++) {
+ struct cache_entry *ce2 = o->src_index->cache[i];
+ int len = ce_namelen(ce2);
if (len < namelen ||
- strncmp(ce->name, ce->name, namelen) ||
- ce->name[namelen] != '/')
+ strncmp(ce->name, ce2->name, namelen) ||
+ ce2->name[namelen] != '/')
break;
/*
- * ce->name is an entry in the subdirectory.
+ * ce2->name is an entry in the subdirectory.
*/
- if (!ce_stage(ce)) {
- if (verify_uptodate(ce, o))
+ if (!ce_stage(ce2)) {
+ if (verify_uptodate(ce2, o))
return -1;
- add_entry(o, ce, CE_REMOVE, 0);
+ add_entry(o, ce2, CE_REMOVE, 0);
}
cnt++;
}
@@ -583,11 +565,11 @@ static int verify_absent(struct cache_entry *ce, const char *action,
if (o->index_only || o->reset || !o->update)
return 0;
- if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+ if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
return 0;
if (!lstat(ce->name, &st)) {
- int cnt;
+ int ret;
int dtype = ce_to_dtype(ce);
struct cache_entry *result;
@@ -615,13 +597,15 @@ static int verify_absent(struct cache_entry *ce, const char *action,
* files that are in "foo/" we would lose
* it.
*/
- cnt = verify_clean_subdirectory(ce, action, o);
+ ret = verify_clean_subdirectory(ce, action, o);
+ if (ret < 0)
+ return ret;
/*
* If this removed entries from the index,
* what that means is:
*
- * (1) the caller unpack_trees_rec() saw path/foo
+ * (1) the caller unpack_callback() saw path/foo
* in the index, and it has not removed it because
* it thinks it is handling 'path' as blob with
* D/F conflict;
@@ -634,7 +618,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
* We need to increment it by the number of
* deleted entries here.
*/
- o->pos += cnt;
+ o->pos += ret;
return 0;
}
@@ -940,8 +924,17 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
return -1;
}
}
- else if (newtree)
+ else if (newtree) {
+ if (oldtree && !o->initial_checkout) {
+ /*
+ * deletion of the path was staged;
+ */
+ if (same(oldtree, newtree))
+ return 1;
+ return reject_merge(oldtree, o);
+ }
return merged_entry(newtree, current, o);
+ }
return deleted_entry(oldtree, current, o);
}