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:
parent
88f6dbaf99
commit
5c47f4c6e7
@ -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);
|
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 *old_name = patch->old_name;
|
||||||
const char *new_name = patch->new_name;
|
int stat_ret = 0;
|
||||||
const char *name = old_name ? old_name : new_name;
|
unsigned st_mode = 0;
|
||||||
struct cache_entry *ce = NULL;
|
|
||||||
int ok_if_exists;
|
|
||||||
|
|
||||||
patch->rejected = 1; /* we will drop this after we succeed */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that we do not have local modifications from the
|
* Make sure that we do not have local modifications from the
|
||||||
@ -2284,23 +2279,25 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
|||||||
* we have the preimage file to be patched in the work tree,
|
* we have the preimage file to be patched in the work tree,
|
||||||
* unless --cached, which tells git to apply only in the index.
|
* unless --cached, which tells git to apply only in the index.
|
||||||
*/
|
*/
|
||||||
if (old_name) {
|
if (!old_name)
|
||||||
int stat_ret = 0;
|
return 0;
|
||||||
unsigned st_mode = 0;
|
|
||||||
|
|
||||||
if (!cached)
|
assert(patch->is_new <= 0);
|
||||||
stat_ret = lstat(old_name, &st);
|
if (!cached) {
|
||||||
|
stat_ret = lstat(old_name, st);
|
||||||
|
if (stat_ret && errno != ENOENT)
|
||||||
|
return error("%s: %s", old_name, strerror(errno));
|
||||||
|
}
|
||||||
if (check_index) {
|
if (check_index) {
|
||||||
int pos = cache_name_pos(old_name, strlen(old_name));
|
int pos = cache_name_pos(old_name, strlen(old_name));
|
||||||
if (pos < 0)
|
if (pos < 0) {
|
||||||
return error("%s: does not exist in index",
|
if (patch->is_new < 0)
|
||||||
old_name);
|
goto is_new;
|
||||||
ce = active_cache[pos];
|
return error("%s: does not exist in index", old_name);
|
||||||
|
}
|
||||||
|
*ce = active_cache[pos];
|
||||||
if (stat_ret < 0) {
|
if (stat_ret < 0) {
|
||||||
struct checkout costate;
|
struct checkout costate;
|
||||||
if (errno != ENOENT)
|
|
||||||
return error("%s: %s", old_name,
|
|
||||||
strerror(errno));
|
|
||||||
/* checkout */
|
/* checkout */
|
||||||
costate.base_dir = "";
|
costate.base_dir = "";
|
||||||
costate.base_dir_len = 0;
|
costate.base_dir_len = 0;
|
||||||
@ -2308,22 +2305,22 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
|||||||
costate.quiet = 0;
|
costate.quiet = 0;
|
||||||
costate.not_new = 0;
|
costate.not_new = 0;
|
||||||
costate.refresh_cache = 1;
|
costate.refresh_cache = 1;
|
||||||
if (checkout_entry(ce,
|
if (checkout_entry(*ce, &costate, NULL) ||
|
||||||
&costate,
|
lstat(old_name, st))
|
||||||
NULL) ||
|
|
||||||
lstat(old_name, &st))
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!cached && verify_index_match(ce, &st))
|
if (!cached && verify_index_match(*ce, st))
|
||||||
return error("%s: does not match index",
|
return error("%s: does not match index", old_name);
|
||||||
old_name);
|
|
||||||
if (cached)
|
if (cached)
|
||||||
st_mode = ce->ce_mode;
|
st_mode = (*ce)->ce_mode;
|
||||||
} else if (stat_ret < 0)
|
} else if (stat_ret < 0) {
|
||||||
|
if (patch->is_new < 0)
|
||||||
|
goto is_new;
|
||||||
return error("%s: %s", old_name, strerror(errno));
|
return error("%s: %s", old_name, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
if (!cached)
|
if (!cached)
|
||||||
st_mode = ce_mode_from_stat(ce, st.st_mode);
|
st_mode = ce_mode_from_stat(*ce, st->st_mode);
|
||||||
|
|
||||||
if (patch->is_new < 0)
|
if (patch->is_new < 0)
|
||||||
patch->is_new = 0;
|
patch->is_new = 0;
|
||||||
@ -2334,7 +2331,31 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
|||||||
if (st_mode != patch->old_mode)
|
if (st_mode != patch->old_mode)
|
||||||
fprintf(stderr, "warning: %s has type %o, expected %o\n",
|
fprintf(stderr, "warning: %s has type %o, expected %o\n",
|
||||||
old_name, st_mode, patch->old_mode);
|
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 &&
|
if (new_name && prev_patch && 0 < prev_patch->is_delete &&
|
||||||
!strcmp(prev_patch->old_name, new_name))
|
!strcmp(prev_patch->old_name, new_name))
|
||||||
|
Loading…
Reference in New Issue
Block a user