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>
This commit is contained in:
Junio C Hamano 2008-05-17 01:51:31 -07:00
parent 88f6dbaf99
commit 5c47f4c6e7

View File

@ -2267,6 +2267,79 @@ 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_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
{
const char *old_name = patch->old_name;
int stat_ret = 0;
unsigned st_mode = 0;
/*
* Make sure that we do not have local modifications from the
* index when we are looking at the index. Also make sure
* 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)
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)
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;
@ -2275,66 +2348,14 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
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 */
/*
* Make sure that we do not have local modifications from the
* index when we are looking at the index. Also make sure
* 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 (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);
}
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))