if ((merge_status < 0) || !result_buf.ptr)
ret = err(o, _("Failed to execute internal merge"));
- if (!ret && write_sha1_file(result_buf.ptr, result_buf.size,
- blob_type, result->oid.hash))
+ if (!ret &&
+ write_object_file(result_buf.ptr, result_buf.size,
+ blob_type, &result->oid))
ret = err(o, _("Unable to add %s to database"),
a->path);
&b->oid,
!o->call_depth);
} else if (S_ISLNK(a->mode)) {
- oidcpy(&result->oid, &a->oid);
-
- if (!oid_eq(&a->oid, &b->oid))
- result->clean = 0;
+ switch (o->recursive_variant) {
+ case MERGE_RECURSIVE_NORMAL:
+ oidcpy(&result->oid, &a->oid);
+ if (!oid_eq(&a->oid, &b->oid))
+ result->clean = 0;
+ break;
+ case MERGE_RECURSIVE_OURS:
+ oidcpy(&result->oid, &a->oid);
+ break;
+ case MERGE_RECURSIVE_THEIRS:
+ oidcpy(&result->oid, &b->oid);
+ break;
+ }
} else
die("BUG: unsupported object type in the tree");
}
add = filespec_from_entry(&other, dst_entry, stage ^ 1);
if (add) {
+ int ren_src_was_dirty = was_dirty(o, rename->path);
char *add_name = unique_path(o, rename->path, other_branch);
if (update_file(o, 0, &add->oid, add->mode, add_name))
return -1;
- remove_file(o, 0, rename->path, 0);
+ if (ren_src_was_dirty) {
+ output(o, 1, _("Refusing to lose dirty file at %s"),
+ rename->path);
+ }
+ /*
+ * Because the double negatives somehow keep confusing me...
+ * 1) update_wd iff !ren_src_was_dirty.
+ * 2) no_wd iff !update_wd
+ * 3) so, no_wd == !!ren_src_was_dirty == ren_src_was_dirty
+ */
+ remove_file(o, 0, rename->path, ren_src_was_dirty);
dst_name = unique_path(o, rename->path, cur_branch);
} else {
if (dir_in_way(rename->path, !o->call_depth, 0)) {
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);
- if (would_lose_untracked(path))
+ if (was_dirty(o, path))
+ output(o, 1, _("Refusing to lose dirty file at %s"),
+ path);
+ else if (would_lose_untracked(path))
/*
* Only way we get here is if both renames were from
* a directory rename AND user had an untracked file
char *new_path;
struct diff_filepair *pair = pairs->queue[i];
- if (pair->status == 'D')
+ if (pair->status != 'A' && pair->status != 'R')
continue;
dir_rename_ent = check_dir_renamed(pair->two->path,
dir_renames);
{
struct string_list_item *item;
int stage = (tree == a_tree ? 2 : 3);
+ int update_wd;
/*
* In all cases where we can do directory rename detection,
* saying the file would have been overwritten), but it might
* be dirty, though.
*/
- remove_file(o, 1, pair->two->path, 0 /* no_wd */);
+ update_wd = !was_dirty(o, pair->two->path);
+ if (!update_wd)
+ output(o, 1, _("Refusing to lose dirty file at %s"),
+ pair->two->path);
+ remove_file(o, 1, pair->two->path, !update_wd);
/* Find or create a new re->dst_entry */
item = string_list_lookup(entries, new_path);
struct diff_filepair *pair = pairs->queue[i];
char *new_path; /* non-NULL only with directory renames */
- if (pair->status == 'D') {
+ if (pair->status != 'A' && pair->status != 'R') {
diff_free_filepair(pair);
continue;
}
if (mfi.clean && !df_conflict_remains &&
oid_eq(&mfi.oid, a_oid) && mfi.mode == a_mode) {
- int path_renamed_outside_HEAD;
output(o, 3, _("Skipped %s (merged same as existing)"), path);
/*
* The content merge resulted in the same file contents we
* are recorded at the correct path (which may not be true
* if the merge involves a rename).
*/
- path_renamed_outside_HEAD = !path2 || !strcmp(path, path2);
- if (!path_renamed_outside_HEAD) {
+ if (was_tracked(path)) {
add_cacheinfo(o, mfi.mode, &mfi.oid, path,
0, (!o->call_depth), 0);
return mfi.clean;
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
clean = merge_recursive(o, head_commit, next_commit, ca,
result);
- if (clean < 0)
+ if (clean < 0) {
+ rollback_lock_file(&lock);
return clean;
+ }
if (active_cache_changed &&
write_locked_index(&the_index, &lock, COMMIT_LOCK))
return err(o, _("Unable to write index."));
+ rollback_lock_file(&lock);
return clean ? 0 : 1;
}