builtin-apply: keep information about files to be deleted
Example correct diff generated by `diff -M -B' might look like this: diff --git a/file1 b/file2 similarity index 100% rename from file1 rename to file2 diff --git a/file2 b/file1 similarity index 100% rename from file2 rename to file1 Information about removing `file2' comes after information about creation of new `file2' (renamed from `file1'). Existing implementation isn't able to apply such patch, because it has to know in advance which files will be removed. This patch populates fn_table with information about removal of files before calling check_patch() for each patch to be applied. Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
d8c81dfcaf
commit
7fac0eef91
@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* item->util in the filename table records the status of the path.
|
||||||
|
* Usually it points at a patch (whose result records the contents
|
||||||
|
* of it after applying it), but it could be PATH_WAS_DELETED for a
|
||||||
|
* path that a previously applied patch has already removed.
|
||||||
|
*/
|
||||||
|
#define PATH_TO_BE_DELETED ((struct patch *) -2)
|
||||||
|
#define PATH_WAS_DELETED ((struct patch *) -1)
|
||||||
|
|
||||||
|
static int to_be_deleted(struct patch *patch)
|
||||||
|
{
|
||||||
|
return patch == PATH_TO_BE_DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int was_deleted(struct patch *patch)
|
||||||
|
{
|
||||||
|
return patch == PATH_WAS_DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
static void add_to_fn_table(struct patch *patch)
|
static void add_to_fn_table(struct patch *patch)
|
||||||
{
|
{
|
||||||
struct string_list_item *item;
|
struct string_list_item *item;
|
||||||
@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch)
|
|||||||
*/
|
*/
|
||||||
if ((patch->new_name == NULL) || (patch->is_rename)) {
|
if ((patch->new_name == NULL) || (patch->is_rename)) {
|
||||||
item = string_list_insert(patch->old_name, &fn_table);
|
item = string_list_insert(patch->old_name, &fn_table);
|
||||||
item->util = (struct patch *) -1;
|
item->util = PATH_WAS_DELETED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare_fn_table(struct patch *patch)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* store information about incoming file deletion
|
||||||
|
*/
|
||||||
|
while (patch) {
|
||||||
|
if ((patch->new_name == NULL) || (patch->is_rename)) {
|
||||||
|
struct string_list_item *item;
|
||||||
|
item = string_list_insert(patch->old_name, &fn_table);
|
||||||
|
item->util = PATH_TO_BE_DELETED;
|
||||||
|
}
|
||||||
|
patch = patch->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
|||||||
struct patch *tpatch;
|
struct patch *tpatch;
|
||||||
|
|
||||||
if (!(patch->is_copy || patch->is_rename) &&
|
if (!(patch->is_copy || patch->is_rename) &&
|
||||||
((tpatch = in_fn_table(patch->old_name)) != NULL)) {
|
(tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
|
||||||
if (tpatch == (struct patch *) -1) {
|
if (was_deleted(tpatch)) {
|
||||||
return error("patch %s has been renamed/deleted",
|
return error("patch %s has been renamed/deleted",
|
||||||
patch->old_name);
|
patch->old_name);
|
||||||
}
|
}
|
||||||
@ -2399,10 +2433,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
|
|||||||
assert(patch->is_new <= 0);
|
assert(patch->is_new <= 0);
|
||||||
|
|
||||||
if (!(patch->is_copy || patch->is_rename) &&
|
if (!(patch->is_copy || patch->is_rename) &&
|
||||||
(tpatch = in_fn_table(old_name)) != NULL) {
|
(tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
|
||||||
if (tpatch == (struct patch *) -1) {
|
if (was_deleted(tpatch))
|
||||||
return error("%s: has been deleted/renamed", old_name);
|
return error("%s: has been deleted/renamed", old_name);
|
||||||
}
|
|
||||||
st_mode = tpatch->new_mode;
|
st_mode = tpatch->new_mode;
|
||||||
} else if (!cached) {
|
} else if (!cached) {
|
||||||
stat_ret = lstat(old_name, st);
|
stat_ret = lstat(old_name, st);
|
||||||
@ -2410,6 +2443,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
|
|||||||
return error("%s: %s", old_name, strerror(errno));
|
return error("%s: %s", old_name, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (to_be_deleted(tpatch))
|
||||||
|
tpatch = NULL;
|
||||||
|
|
||||||
if (check_index && !tpatch) {
|
if (check_index && !tpatch) {
|
||||||
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) {
|
||||||
@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch)
|
|||||||
const char *new_name = patch->new_name;
|
const char *new_name = patch->new_name;
|
||||||
const char *name = old_name ? old_name : new_name;
|
const char *name = old_name ? old_name : new_name;
|
||||||
struct cache_entry *ce = NULL;
|
struct cache_entry *ce = NULL;
|
||||||
|
struct patch *tpatch;
|
||||||
int ok_if_exists;
|
int ok_if_exists;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch)
|
|||||||
return status;
|
return status;
|
||||||
old_name = patch->old_name;
|
old_name = patch->old_name;
|
||||||
|
|
||||||
if (in_fn_table(new_name) == (struct patch *) -1)
|
if ((tpatch = in_fn_table(new_name)) &&
|
||||||
|
(was_deleted(tpatch) || to_be_deleted(tpatch)))
|
||||||
/*
|
/*
|
||||||
* A type-change diff is always split into a patch to
|
* A type-change diff is always split into a patch to
|
||||||
* delete old, immediately followed by a patch to
|
* delete old, immediately followed by a patch to
|
||||||
@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch)
|
|||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
prepare_fn_table(patch);
|
||||||
while (patch) {
|
while (patch) {
|
||||||
if (apply_verbosely)
|
if (apply_verbosely)
|
||||||
say_patch_name(stderr,
|
say_patch_name(stderr,
|
||||||
|
@ -31,7 +31,7 @@ test_expect_success 'diff -M -B' '
|
|||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'apply' '
|
test_expect_success 'apply' '
|
||||||
git apply diff
|
git apply diff
|
||||||
'
|
'
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user