diff options
| author | Junio C Hamano <gitster@pobox.com> | 2008-05-17 01:51:31 -0700 | 
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2008-05-17 01:51:31 -0700 | 
| commit | 5c47f4c6e71e6de08348f837f38a446a2f2b0ed7 (patch) | |
| tree | c3f388e53beec55d52e14015cbdc3b7771827702 | |
| parent | 88f6dbaf99f43053f86474b28beedd91e77c64d9 (diff) | |
| download | git-5c47f4c6e71e6de08348f837f38a446a2f2b0ed7.tar.gz | |
builtin-apply: accept patch to an empty file
A patch from a foreign SCM (or plain "diff" output) often have both
preimage and postimage filename on ---/+++ lines even for a patch that
creates a new file.  However, when there is a filename for preimage, we
used to insist the file to exist (either in the work tree and/or in the
index).  When we cannot be sure by parsing the patch that it is not a
creation patch, we shouldn't complain when if there is no such a file.
This commit fixes the logic.
Refactor the code that validates the preimage file into a separate
function while we are at it, as it is getting rather big.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
| -rw-r--r-- | builtin-apply.c | 133 | 
1 files changed, 77 insertions, 56 deletions
| diff --git a/builtin-apply.c b/builtin-apply.c index 776e5963b7..10b1f88a3c 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2267,16 +2267,11 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)  	return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);  } -static int check_patch(struct patch *patch, struct patch *prev_patch) +static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)  { -	struct stat st;  	const char *old_name = patch->old_name; -	const char *new_name = patch->new_name; -	const char *name = old_name ? old_name : new_name; -	struct cache_entry *ce = NULL; -	int ok_if_exists; - -	patch->rejected = 1; /* we will drop this after we succeed */ +	int stat_ret = 0; +	unsigned st_mode = 0;  	/*  	 * Make sure that we do not have local modifications from the @@ -2284,58 +2279,84 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)  	 * we have the preimage file to be patched in the work tree,  	 * unless --cached, which tells git to apply only in the index.  	 */ -	if (old_name) { -		int stat_ret = 0; -		unsigned st_mode = 0; - -		if (!cached) -			stat_ret = lstat(old_name, &st); -		if (check_index) { -			int pos = cache_name_pos(old_name, strlen(old_name)); -			if (pos < 0) -				return error("%s: does not exist in index", -					     old_name); -			ce = active_cache[pos]; -			if (stat_ret < 0) { -				struct checkout costate; -				if (errno != ENOENT) -					return error("%s: %s", old_name, -						     strerror(errno)); -				/* checkout */ -				costate.base_dir = ""; -				costate.base_dir_len = 0; -				costate.force = 0; -				costate.quiet = 0; -				costate.not_new = 0; -				costate.refresh_cache = 1; -				if (checkout_entry(ce, -						   &costate, -						   NULL) || -				    lstat(old_name, &st)) -					return -1; -			} -			if (!cached && verify_index_match(ce, &st)) -				return error("%s: does not match index", -					     old_name); -			if (cached) -				st_mode = ce->ce_mode; -		} else if (stat_ret < 0) -			return error("%s: %s", old_name, strerror(errno)); - -		if (!cached) -			st_mode = ce_mode_from_stat(ce, st.st_mode); +	if (!old_name) +		return 0; +	assert(patch->is_new <= 0); +	if (!cached) { +		stat_ret = lstat(old_name, st); +		if (stat_ret && errno != ENOENT) +			return error("%s: %s", old_name, strerror(errno)); +	} +	if (check_index) { +		int pos = cache_name_pos(old_name, strlen(old_name)); +		if (pos < 0) { +			if (patch->is_new < 0) +				goto is_new; +			return error("%s: does not exist in index", old_name); +		} +		*ce = active_cache[pos]; +		if (stat_ret < 0) { +			struct checkout costate; +			/* checkout */ +			costate.base_dir = ""; +			costate.base_dir_len = 0; +			costate.force = 0; +			costate.quiet = 0; +			costate.not_new = 0; +			costate.refresh_cache = 1; +			if (checkout_entry(*ce, &costate, NULL) || +			    lstat(old_name, st)) +				return -1; +		} +		if (!cached && verify_index_match(*ce, st)) +			return error("%s: does not match index", old_name); +		if (cached) +			st_mode = (*ce)->ce_mode; +	} else if (stat_ret < 0) {  		if (patch->is_new < 0) -			patch->is_new = 0; -		if (!patch->old_mode) -			patch->old_mode = st_mode; -		if ((st_mode ^ patch->old_mode) & S_IFMT) -			return error("%s: wrong type", old_name); -		if (st_mode != patch->old_mode) -			fprintf(stderr, "warning: %s has type %o, expected %o\n", -				old_name, st_mode, patch->old_mode); +			goto is_new; +		return error("%s: %s", old_name, strerror(errno));  	} +	if (!cached) +		st_mode = ce_mode_from_stat(*ce, st->st_mode); + +	if (patch->is_new < 0) +		patch->is_new = 0; +	if (!patch->old_mode) +		patch->old_mode = st_mode; +	if ((st_mode ^ patch->old_mode) & S_IFMT) +		return error("%s: wrong type", old_name); +	if (st_mode != patch->old_mode) +		fprintf(stderr, "warning: %s has type %o, expected %o\n", +			old_name, st_mode, patch->old_mode); +	return 0; + + is_new: +	patch->is_new = 1; +	patch->is_delete = 0; +	patch->old_name = NULL; +	return 0; +} + +static int check_patch(struct patch *patch, struct patch *prev_patch) +{ +	struct stat st; +	const char *old_name = patch->old_name; +	const char *new_name = patch->new_name; +	const char *name = old_name ? old_name : new_name; +	struct cache_entry *ce = NULL; +	int ok_if_exists; +	int status; + +	patch->rejected = 1; /* we will drop this after we succeed */ + +	status = check_preimage(patch, &ce, &st); +	if (status) +		return status; +	old_name = patch->old_name; +  	if (new_name && prev_patch && 0 < prev_patch->is_delete &&  	    !strcmp(prev_patch->old_name, new_name))  		/* | 
