diff options
Diffstat (limited to 'unpack-trees.c')
| -rw-r--r-- | unpack-trees.c | 120 | 
1 files changed, 90 insertions, 30 deletions
| diff --git a/unpack-trees.c b/unpack-trees.c index a59f47557a..cba0aca062 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -8,6 +8,36 @@  #include "progress.h"  #include "refs.h" +/* + * Error messages expected by scripts out of plumbing commands such as + * read-tree.  Non-scripted Porcelain is not required to use these messages + * and in fact are encouraged to reword them to better suit their particular + * situation better.  See how "git checkout" replaces not_uptodate_file to + * explain why it does not allow switching between branches when you have + * local changes, for example. + */ +static struct unpack_trees_error_msgs unpack_plumbing_errors = { +	/* would_overwrite */ +	"Entry '%s' would be overwritten by merge. Cannot merge.", + +	/* not_uptodate_file */ +	"Entry '%s' not uptodate. Cannot merge.", + +	/* not_uptodate_dir */ +	"Updating '%s' would lose untracked files in it", + +	/* would_lose_untracked */ +	"Untracked working tree file '%s' would be %s by merge.", + +	/* bind_overlap */ +	"Entry '%s' overlaps with '%s'.  Cannot bind.", +}; + +#define ERRORMSG(o,fld) \ +	( ((o) && (o)->msgs.fld) \ +	? ((o)->msgs.fld) \ +	: (unpack_plumbing_errors.fld) ) +  static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,  	unsigned int set, unsigned int clear)  { @@ -26,11 +56,12 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,   * directories, in case this unlink is the removal of the   * last entry in the directory -- empty directories are removed.   */ -static void unlink_entry(char *name, char *last_symlink) +static void unlink_entry(struct cache_entry *ce)  {  	char *cp, *prev; +	char *name = ce->name; -	if (has_symlink_leading_path(name, last_symlink)) +	if (has_symlink_leading_path(ce_namelen(ce), ce->name))  		return;  	if (unlink(name))  		return; @@ -58,7 +89,6 @@ static int check_updates(struct unpack_trees_options *o)  {  	unsigned cnt = 0, total = 0;  	struct progress *progress = NULL; -	char last_symlink[PATH_MAX];  	struct index_state *index = &o->result;  	int i;  	int errs = 0; @@ -75,24 +105,27 @@ static int check_updates(struct unpack_trees_options *o)  		cnt = 0;  	} -	*last_symlink = '\0';  	for (i = 0; i < index->cache_nr; i++) {  		struct cache_entry *ce = index->cache[i]; -		if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) -			display_progress(progress, ++cnt);  		if (ce->ce_flags & CE_REMOVE) { +			display_progress(progress, ++cnt);  			if (o->update) -				unlink_entry(ce->name, last_symlink); +				unlink_entry(ce);  			remove_index_entry_at(&o->result, i);  			i--;  			continue;  		} +	} + +	for (i = 0; i < index->cache_nr; i++) { +		struct cache_entry *ce = index->cache[i]; +  		if (ce->ce_flags & CE_UPDATE) { +			display_progress(progress, ++cnt);  			ce->ce_flags &= ~CE_UPDATE;  			if (o->update) {  				errs |= checkout_entry(ce, &state, NULL); -				*last_symlink = '\0';  			}  		}  	} @@ -325,8 +358,13 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)  	return -1;  } +/* + * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the + * resulting index, -2 on failure to reflect the changes to the work tree. + */  int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)  { +	int ret;  	static struct cache_entry *dfc;  	if (len > MAX_UNPACK_TREES) @@ -371,19 +409,17 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options  		return unpack_failed(o, "Merge requires file-level merging");  	o->src_index = NULL; -	if (check_updates(o)) -		return -1; +	ret = check_updates(o) ? (-2) : 0;  	if (o->dst_index)  		*o->dst_index = o->result; -	return 0; +	return ret;  }  /* Here come the merge functions */ -static int reject_merge(struct cache_entry *ce) +static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)  { -	return error("Entry '%s' would be overwritten by merge. Cannot merge.", -		     ce->name); +	return error(ERRORMSG(o, would_overwrite), ce->name);  }  static int same(struct cache_entry *a, struct cache_entry *b) @@ -427,7 +463,7 @@ static int verify_uptodate(struct cache_entry *ce,  	if (errno == ENOENT)  		return 0;  	return o->gently ? -1 : -		error("Entry '%s' not uptodate. Cannot merge.", ce->name); +		error(ERRORMSG(o, not_uptodate_file), ce->name);  }  static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o) @@ -514,13 +550,28 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,  	i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);  	if (i)  		return o->gently ? -1 : -			error("Updating '%s' would lose untracked files in it", -			      ce->name); +			error(ERRORMSG(o, not_uptodate_dir), ce->name);  	free(pathbuf);  	return cnt;  }  /* + * This gets called when there was no index entry for the tree entry 'dst', + * but we found a file in the working tree that 'lstat()' said was fine, + * and we're on a case-insensitive filesystem. + * + * See if we can find a case-insensitive match in the index that also + * matches the stat information, and assume it's that other file! + */ +static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst, struct stat *st) +{ +	struct cache_entry *src; + +	src = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1); +	return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID); +} + +/*   * We do not want to remove or overwrite a working tree file that   * is not tracked, unless it is ignored.   */ @@ -532,12 +583,23 @@ 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->name, NULL)) +	if (has_symlink_leading_path(ce_namelen(ce), ce->name))  		return 0;  	if (!lstat(ce->name, &st)) {  		int cnt;  		int dtype = ce_to_dtype(ce); +		struct cache_entry *result; + +		/* +		 * It may be that the 'lstat()' succeeded even though +		 * target 'ce' was absent, because there is an old +		 * entry that is different only in case.. +		 * +		 * Ignore that lstat() if it matches. +		 */ +		if (ignore_case && icase_exists(o, ce, &st)) +			return 0;  		if (o->dir && excluded(o->dir, ce->name, &dtype))  			/* @@ -581,16 +643,14 @@ static int verify_absent(struct cache_entry *ce, const char *action,  		 * delete this path, which is in a subdirectory that  		 * is being replaced with a blob.  		 */ -		cnt = index_name_pos(&o->result, ce->name, strlen(ce->name)); -		if (0 <= cnt) { -			struct cache_entry *ce = o->result.cache[cnt]; -			if (ce->ce_flags & CE_REMOVE) +		result = index_name_exists(&o->result, ce->name, ce_namelen(ce), 0); +		if (result) { +			if (result->ce_flags & CE_REMOVE)  				return 0;  		}  		return o->gently ? -1 : -			error("Untracked working tree file '%s' " -			      "would be %s by merge.", ce->name, action); +			error(ERRORMSG(o, would_lose_untracked), ce->name, action);  	}  	return 0;  } @@ -722,7 +782,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)  	/* #14, #14ALT, #2ALT */  	if (remote && !df_conflict_head && head_match && !remote_match) {  		if (index && !same(index, remote) && !same(index, head)) -			return o->gently ? -1 : reject_merge(index); +			return o->gently ? -1 : reject_merge(index, o);  		return merged_entry(remote, index, o);  	}  	/* @@ -730,7 +790,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)  	 * make sure that it matches head.  	 */  	if (index && !same(index, head)) -		return o->gently ? -1 : reject_merge(index); +		return o->gently ? -1 : reject_merge(index, o);  	if (head) {  		/* #5ALT, #15 */ @@ -872,11 +932,11 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)  		else {  			/* all other failures */  			if (oldtree) -				return o->gently ? -1 : reject_merge(oldtree); +				return o->gently ? -1 : reject_merge(oldtree, o);  			if (current) -				return o->gently ? -1 : reject_merge(current); +				return o->gently ? -1 : reject_merge(current, o);  			if (newtree) -				return o->gently ? -1 : reject_merge(newtree); +				return o->gently ? -1 : reject_merge(newtree, o);  			return -1;  		}  	} @@ -902,7 +962,7 @@ int bind_merge(struct cache_entry **src,  			     o->merge_size);  	if (a && old)  		return o->gently ? -1 : -			error("Entry '%s' overlaps with '%s'.  Cannot bind.", a->name, old->name); +			error(ERRORMSG(o, bind_overlap), a->name, old->name);  	if (!a)  		return keep_entry(old, o);  	else | 
