@ -742,12 +742,12 @@ static int make_room_for_path(struct merge_options *o, const char *path)
@@ -742,12 +742,12 @@ static int make_room_for_path(struct merge_options *o, const char *path)
return error(msg, path, _(": perhaps a D/F conflict?"));
}
static void update_file_flags(struct merge_options *o,
const struct object_id *oid,
unsigned mode,
const char *path,
int update_cache,
int update_wd)
static int update_file_flags(struct merge_options *o,
const struct object_id *oid,
unsigned mode,
const char *path,
int update_cache,
int update_wd)
{
if (o->call_depth)
update_wd = 0;
@ -783,8 +783,7 @@ static void update_file_flags(struct merge_options *o,
@@ -783,8 +783,7 @@ static void update_file_flags(struct merge_options *o,
if (make_room_for_path(o, path) < 0) {
update_wd = 0;
free(buf);
goto update_index;
goto free_buf;
}
if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
int fd;
@ -807,20 +806,22 @@ static void update_file_flags(struct merge_options *o,
@@ -807,20 +806,22 @@ static void update_file_flags(struct merge_options *o,
} else
die(_("do not know what to do with %06o %s '%s'"),
mode, oid_to_hex(oid), path);
free_buf:
free(buf);
}
update_index:
if (update_cache)
add_cacheinfo(mode, oid, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
return 0;
}
static void update_file(struct merge_options *o,
int clean,
const struct object_id *oid,
unsigned mode,
const char *path)
static int update_file(struct merge_options *o,
int clean,
const struct object_id *oid,
unsigned mode,
const char *path)
{
update_file_flags(o, oid, mode, path, o->call_depth || clean, !o->call_depth);
return update_file_flags(o, oid, mode, path, o->call_depth || clean, !o->call_depth);
}
/* Low level file merging, update and removal */
@ -1019,7 +1020,7 @@ static int merge_file_one(struct merge_options *o,
@@ -1019,7 +1020,7 @@ static int merge_file_one(struct merge_options *o,
return merge_file_1(o, &one, &a, &b, branch1, branch2, mfi);
}
static void handle_change_delete(struct merge_options *o,
static int handle_change_delete(struct merge_options *o,
const char *path,
const struct object_id *o_oid, int o_mode,
const struct object_id *a_oid, int a_mode,
@ -1027,6 +1028,7 @@ static void handle_change_delete(struct merge_options *o,
@@ -1027,6 +1028,7 @@ static void handle_change_delete(struct merge_options *o,
const char *change, const char *change_past)
{
char *renamed = NULL;
int ret = 0;
if (dir_in_way(path, !o->call_depth)) {
renamed = unique_path(o, path, a_oid ? o->branch1 : o->branch2);
}
@ -1037,21 +1039,23 @@ static void handle_change_delete(struct merge_options *o,
@@ -1037,21 +1039,23 @@ static void handle_change_delete(struct merge_options *o,
* correct; since there is no true "middle point" between
* them, simply reuse the base version for virtual merge base.
*/
remove_file_from_cache(path);
update_file(o, 0, o_oid, o_mode, renamed ? renamed : path);
ret = remove_file_from_cache(path);
if (!ret)
ret = update_file(o, 0, o_oid, o_mode,
renamed ? renamed : path);
} else if (!a_oid) {
if (!renamed) {
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
"and %s in %s. Version %s of %s left in tree."),
change, path, o->branch1, change_past,
o->branch2, o->branch2, path);
update_file(o, 0, b_oid, b_mode, path);
ret = update_file(o, 0, b_oid, b_mode, path);
} else {
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
"and %s in %s. Version %s of %s left in tree at %s."),
change, path, o->branch1, change_past,
o->branch2, o->branch2, path, renamed);
update_file(o, 0, b_oid, b_mode, renamed);
ret = update_file(o, 0, b_oid, b_mode, renamed);
}
} else {
if (!renamed) {
@ -1064,7 +1068,7 @@ static void handle_change_delete(struct merge_options *o,
@@ -1064,7 +1068,7 @@ static void handle_change_delete(struct merge_options *o,
"and %s in %s. Version %s of %s left in tree at %s."),
change, path, o->branch2, change_past,
o->branch1, o->branch1, path, renamed);
update_file(o, 0, a_oid, a_mode, renamed);
ret = update_file(o, 0, a_oid, a_mode, renamed);
}
/*
* No need to call update_file() on path when !renamed, since
@ -1074,9 +1078,11 @@ static void handle_change_delete(struct merge_options *o,
@@ -1074,9 +1078,11 @@ static void handle_change_delete(struct merge_options *o,
*/
}
free(renamed);
return ret;
}
static void conflict_rename_delete(struct merge_options *o,
static int conflict_rename_delete(struct merge_options *o,
struct diff_filepair *pair,
const char *rename_branch,
const char *other_branch)
@ -1096,21 +1102,20 @@ static void conflict_rename_delete(struct merge_options *o,
@@ -1096,21 +1102,20 @@ static void conflict_rename_delete(struct merge_options *o,
b_mode = dest->mode;
}
handle_change_delete(o,
o->call_depth ? orig->path : dest->path,
&orig->oid, orig->mode,
a_oid, a_mode,
b_oid, b_mode,
_("rename"), _("renamed"));
if (o->call_depth) {
remove_file_from_cache(dest->path);
} else {
update_stages(dest->path, NULL,
rename_branch == o->branch1 ? dest : NULL,
rename_branch == o->branch1 ? NULL : dest);
}
if (handle_change_delete(o,
o->call_depth ? orig->path : dest->path,
&orig->oid, orig->mode,
a_oid, a_mode,
b_oid, b_mode,
_("rename"), _("renamed")))
return -1;
if (o->call_depth)
return remove_file_from_cache(dest->path);
else
return update_stages(dest->path, NULL,
rename_branch == o->branch1 ? dest : NULL,
rename_branch == o->branch1 ? NULL : dest);
}
static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
@ -1126,7 +1131,7 @@ static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
@@ -1126,7 +1131,7 @@ static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
return target;
}
static void handle_file(struct merge_options *o,
static int handle_file(struct merge_options *o,
struct diff_filespec *rename,
int stage,
struct rename_conflict_info *ci)
@ -1136,6 +1141,7 @@ static void handle_file(struct merge_options *o,
@@ -1136,6 +1141,7 @@ static void handle_file(struct merge_options *o,
const char *cur_branch, *other_branch;
struct diff_filespec other;
struct diff_filespec *add;
int ret;
if (stage == 2) {
dst_entry = ci->dst_entry1;
@ -1150,7 +1156,8 @@ static void handle_file(struct merge_options *o,
@@ -1150,7 +1156,8 @@ static void handle_file(struct merge_options *o,
add = filespec_from_entry(&other, dst_entry, stage ^ 1);
if (add) {
char *add_name = unique_path(o, rename->path, other_branch);
update_file(o, 0, &add->oid, add->mode, add_name);
if (update_file(o, 0, &add->oid, add->mode, add_name))
return -1;
remove_file(o, 0, rename->path, 0);
dst_name = unique_path(o, rename->path, cur_branch);
@ -1161,17 +1168,20 @@ static void handle_file(struct merge_options *o,
@@ -1161,17 +1168,20 @@ static void handle_file(struct merge_options *o,
rename->path, other_branch, dst_name);
}
}
update_file(o, 0, &rename->oid, rename->mode, dst_name);
if (stage == 2)
update_stages(rename->path, NULL, rename, add);
if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
; /* fall through, do allow dst_name to be released */
else if (stage == 2)
ret = update_stages(rename->path, NULL, rename, add);
else
update_stages(rename->path, NULL, add, rename);
ret = update_stages(rename->path, NULL, add, rename);
if (dst_name != rename->path)
free(dst_name);
return ret;
}
static void conflict_rename_rename_1to2(struct merge_options *o,
static int conflict_rename_rename_1to2(struct merge_options *o,
struct rename_conflict_info *ci)
{
/* One file was renamed in both branches, but to different names. */
@ -1194,14 +1204,16 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
@@ -1194,14 +1204,16 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
&a->oid, a->mode,
&b->oid, b->mode,
ci->branch1, ci->branch2, &mfi))
return;
return -1;
/*
* FIXME: For rename/add-source conflicts (if we could detect
* such), this is wrong. We should instead find a unique
* pathname and then either rename the add-source file to that
* unique path, or use that unique path instead of src here.
*/
update_file(o, 0, &mfi.oid, mfi.mode, one->path);
if (update_file(o, 0, &mfi.oid, mfi.mode, one->path))
return -1;
/*
* Above, we put the merged content at the merge-base's
@ -1212,22 +1224,26 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
@@ -1212,22 +1224,26 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
* resolving the conflict at that path in its favor.
*/
add = filespec_from_entry(&other, ci->dst_entry1, 2 ^ 1);
if (add)
update_file(o, 0, &add->oid, add->mode, a->path);
if (add) {
if (update_file(o, 0, &add->oid, add->mode, a->path))
return -1;
}
else
remove_file_from_cache(a->path);
add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);
if (add)
update_file(o, 0, &add->oid, add->mode, b->path);
if (add) {
if (update_file(o, 0, &add->oid, add->mode, b->path))
return -1;
}
else
remove_file_from_cache(b->path);
} else {
handle_file(o, a, 2, ci);
handle_file(o, b, 3, ci);
}
} else if (handle_file(o, a, 2, ci) || handle_file(o, b, 3, ci))
return -1;
return 0;
}
static void conflict_rename_rename_2to1(struct merge_options *o,
static int conflict_rename_rename_2to1(struct merge_options *o,
struct rename_conflict_info *ci)
{
/* Two files, a & b, were renamed to the same thing, c. */
@ -1238,6 +1254,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
@@ -1238,6 +1254,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
char *path = c1->path; /* == c2->path */
struct merge_file_info mfi_c1;
struct merge_file_info mfi_c2;
int ret;
output(o, 1, _("CONFLICT (rename/rename): "
"Rename %s->%s in %s. "
@ -1254,7 +1271,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
@@ -1254,7 +1271,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
merge_file_special_markers(o, b, &ci->ren2_other, c2,
o->branch1, ci->ren2_other.path,
o->branch2, c2->path, &mfi_c2))
return;
return -1;
if (o->call_depth) {
/*
@ -1265,19 +1282,25 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
@@ -1265,19 +1282,25 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
* again later for the non-recursive merge.
*/
remove_file(o, 0, path, 0);
update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, a->path);
update_file(o, 0, &mfi_c2.oid, mfi_c2.mode, b->path);
ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, a->path);
if (!ret)
ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
b->path);
} else {
char *new_path1 = unique_path(o, path, ci->branch1);
char *new_path2 = unique_path(o, path, ci->branch2);
output(o, 1, _("Renaming %s to %s and %s to %s instead"),
a->path, new_path1, b->path, new_path2);
remove_file(o, 0, path, 0);
update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, new_path1);
update_file(o, 0, &mfi_c2.oid, mfi_c2.mode, new_path2);
ret = update_file(o, 0, &mfi_c1.oid, mfi_c1.mode, new_path1);
if (!ret)
ret = update_file(o, 0, &mfi_c2.oid, mfi_c2.mode,
new_path2);
free(new_path2);
free(new_path1);
}
return ret;
}
static int process_renames(struct merge_options *o,
@ -1462,12 +1485,13 @@ static int process_renames(struct merge_options *o,
@@ -1462,12 +1485,13 @@ static int process_renames(struct merge_options *o,
* update_file_flags() instead of
* update_file().
*/
update_file_flags(o,
&ren1->pair->two->oid,
ren1->pair->two->mode,
ren1_dst,
1, /* update_cache */
0 /* update_wd */);
if (update_file_flags(o,
&ren1->pair->two->oid,
ren1->pair->two->mode,
ren1_dst,
1, /* update_cache */
0 /* update_wd */))
clean_merge = -1;
} else if (!oid_eq(&dst_other.oid, &null_oid)) {
clean_merge = 0;
try_merge = 1;
@ -1482,22 +1506,28 @@ static int process_renames(struct merge_options *o,
@@ -1482,22 +1506,28 @@ static int process_renames(struct merge_options *o,
ren1->pair->two->mode,
&dst_other.oid,
dst_other.mode,
branch1, branch2, &mfi))
return -1;
branch1, branch2, &mfi)) {
clean_merge = -1;
goto cleanup_and_return;
}
output(o, 1, _("Adding merged %s"), ren1_dst);
update_file(o, 0, &mfi.oid,
mfi.mode, ren1_dst);
if (update_file(o, 0, &mfi.oid,
mfi.mode, ren1_dst))
clean_merge = -1;
try_merge = 0;
} else {
char *new_path = unique_path(o, ren1_dst, branch2);
output(o, 1, _("Adding as %s instead"), new_path);
update_file(o, 0, &dst_other.oid,
dst_other.mode, new_path);
if (update_file(o, 0, &dst_other.oid,
dst_other.mode, new_path))
clean_merge = -1;
free(new_path);
}
} else
try_merge = 1;
if (clean_merge < 0)
goto cleanup_and_return;
if (try_merge) {
struct diff_filespec *one, *a, *b;
src_other.path = (char *)ren1_src;
@ -1524,6 +1554,7 @@ static int process_renames(struct merge_options *o,
@@ -1524,6 +1554,7 @@ static int process_renames(struct merge_options *o,
}
}
}
cleanup_and_return:
string_list_clear(&a_by_dst, 0);
string_list_clear(&b_by_dst, 0);
@ -1586,18 +1617,18 @@ error_return:
@@ -1586,18 +1617,18 @@ error_return:
return ret;
}
static void handle_modify_delete(struct merge_options *o,
static int handle_modify_delete(struct merge_options *o,
const char *path,
struct object_id *o_oid, int o_mode,
struct object_id *a_oid, int a_mode,
struct object_id *b_oid, int b_mode)
{
handle_change_delete(o,
path,
o_oid, o_mode,
a_oid, a_mode,
b_oid, b_mode,
_("modify"), _("modified"));
return handle_change_delete(o,
path,
o_oid, o_mode,
a_oid, a_mode,
b_oid, b_mode,
_("modify"), _("modified"));
}
static int merge_content(struct merge_options *o,
@ -1671,7 +1702,8 @@ static int merge_content(struct merge_options *o,
@@ -1671,7 +1702,8 @@ static int merge_content(struct merge_options *o,
output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
reason, path);
if (rename_conflict_info && !df_conflict_remains)
update_stages(path, &one, &a, &b);
if (update_stages(path, &one, &a, &b))
return -1;
}
if (df_conflict_remains) {
@ -1679,30 +1711,33 @@ static int merge_content(struct merge_options *o,
@@ -1679,30 +1711,33 @@ static int merge_content(struct merge_options *o,
if (o->call_depth) {
remove_file_from_cache(path);
} else {
if (!mfi.clean)
update_stages(path, &one, &a, &b);
else {
if (!mfi.clean) {
if (update_stages(path, &one, &a, &b))
return -1;
} else {
int file_from_stage2 = was_tracked(path);
struct diff_filespec merged;
oidcpy(&merged.oid, &mfi.oid);
merged.mode = mfi.mode;
update_stages(path, NULL,
file_from_stage2 ? &merged : NULL,
file_from_stage2 ? NULL : &merged);
if (update_stages(path, NULL,
file_from_stage2 ? &merged : NULL,
file_from_stage2 ? NULL : &merged))
return -1;
}
}
new_path = unique_path(o, path, rename_conflict_info->branch1);
output(o, 1, _("Adding as %s instead"), new_path);
update_file(o, 0, &mfi.oid, mfi.mode, new_path);
if (update_file(o, 0, &mfi.oid, mfi.mode, new_path)) {
free(new_path);
return -1;
}
free(new_path);
mfi.clean = 0;
} else {
update_file(o, mfi.clean, &mfi.oid, mfi.mode, path);
}
} else if (update_file(o, mfi.clean, &mfi.oid, mfi.mode, path))
return -1;
return mfi.clean;
}
/* Per entry merge function */
@ -1730,17 +1765,21 @@ static int process_entry(struct merge_options *o,
@@ -1730,17 +1765,21 @@ static int process_entry(struct merge_options *o,
break;
case RENAME_DELETE:
clean_merge = 0;
conflict_rename_delete(o, conflict_info->pair1,
conflict_info->branch1,
conflict_info->branch2);
if (conflict_rename_delete(o,
conflict_info->pair1,
conflict_info->branch1,
conflict_info->branch2))
clean_merge = -1;
break;
case RENAME_ONE_FILE_TO_TWO:
clean_merge = 0;
conflict_rename_rename_1to2(o, conflict_info);
if (conflict_rename_rename_1to2(o, conflict_info))
clean_merge = -1;
break;
case RENAME_TWO_FILES_TO_ONE:
clean_merge = 0;
conflict_rename_rename_2to1(o, conflict_info);
if (conflict_rename_rename_2to1(o, conflict_info))
clean_merge = -1;
break;
default:
entry->processed = 0;
@ -1760,8 +1799,9 @@ static int process_entry(struct merge_options *o,
@@ -1760,8 +1799,9 @@ static int process_entry(struct merge_options *o,
} else {
/* Modify/delete; deleted side may have put a directory in the way */
clean_merge = 0;
handle_modify_delete(o, path, o_oid, o_mode,
a_oid, a_mode, b_oid, b_mode);
if (handle_modify_delete(o, path, o_oid, o_mode,
a_oid, a_mode, b_oid, b_mode))
clean_merge = -1;
}
} else if ((!o_oid && a_oid && !b_oid) ||
(!o_oid && !a_oid && b_oid)) {
@ -1793,14 +1833,16 @@ static int process_entry(struct merge_options *o,
@@ -1793,14 +1833,16 @@ static int process_entry(struct merge_options *o,
output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
"Adding %s as %s"),
conf, path, other_branch, path, new_path);
update_file(o, 0, oid, mode, new_path);
if (o->call_depth)
if (update_file(o, 0, oid, mode, new_path))
clean_merge = -1;
else if (o->call_depth)
remove_file_from_cache(path);
free(new_path);
} else {
output(o, 2, _("Adding %s"), path);
/* do not overwrite file if already present */
update_file_flags(o, oid, mode, path, 1, !a_oid);
if (update_file_flags(o, oid, mode, path, 1, !a_oid))
clean_merge = -1;
}
} else if (a_oid && b_oid) {
/* Case C: Added in both (check for same permissions) and */
@ -1863,12 +1905,18 @@ int merge_trees(struct merge_options *o,
@@ -1863,12 +1905,18 @@ int merge_trees(struct merge_options *o,
re_head = get_renames(o, head, common, head, merge, entries);
re_merge = get_renames(o, merge, common, head, merge, entries);
clean = process_renames(o, re_head, re_merge);
if (clean < 0)
return clean;
for (i = entries->nr-1; 0 <= i; i--) {
const char *path = entries->items[i].string;
struct stage_data *e = entries->items[i].util;
if (!e->processed
&& !process_entry(o, path, e))
clean = 0;
if (!e->processed) {
int ret = process_entry(o, path, e);
if (!ret)
clean = 0;
else if (ret < 0)
return ret;
}
}
for (i = 0; i < entries->nr; i++) {
struct stage_data *e = entries->items[i].util;