summaryrefslogtreecommitdiff
path: root/merge-recursive.c
diff options
context:
space:
mode:
Diffstat (limited to 'merge-recursive.c')
-rw-r--r--merge-recursive.c80
1 files changed, 59 insertions, 21 deletions
diff --git a/merge-recursive.c b/merge-recursive.c
index 2ecf495cc2..0c0d48624d 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -228,7 +228,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
strbuf_addf(&o->obuf, "virtual %s\n",
merge_remote_util(commit)->name);
else {
- strbuf_add_unique_abbrev(&o->obuf, commit->object.oid.hash,
+ strbuf_add_unique_abbrev(&o->obuf, &commit->object.oid,
DEFAULT_ABBREV);
strbuf_addch(&o->obuf, ' ');
if (parse_commit(commit) != 0)
@@ -335,7 +335,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
return result;
}
-static int save_files_dirs(const unsigned char *sha1,
+static int save_files_dirs(const struct object_id *oid,
struct strbuf *base, const char *path,
unsigned int mode, int stage, void *context)
{
@@ -370,12 +370,12 @@ static struct stage_data *insert_stage_data(const char *path,
{
struct string_list_item *item;
struct stage_data *e = xcalloc(1, sizeof(struct stage_data));
- get_tree_entry(o->object.oid.hash, path,
- e->stages[1].oid.hash, &e->stages[1].mode);
- get_tree_entry(a->object.oid.hash, path,
- e->stages[2].oid.hash, &e->stages[2].mode);
- get_tree_entry(b->object.oid.hash, path,
- e->stages[3].oid.hash, &e->stages[3].mode);
+ get_tree_entry(&o->object.oid, path,
+ &e->stages[1].oid, &e->stages[1].mode);
+ get_tree_entry(&a->object.oid, path,
+ &e->stages[2].oid, &e->stages[2].mode);
+ get_tree_entry(&b->object.oid, path,
+ &e->stages[3].oid, &e->stages[3].mode);
item = string_list_insert(entries, path);
item->util = e;
return e;
@@ -513,6 +513,25 @@ static void record_df_conflict_files(struct merge_options *o,
struct rename {
struct diff_filepair *pair;
+ /*
+ * Purpose of src_entry and dst_entry:
+ *
+ * If 'before' is renamed to 'after' then src_entry will contain
+ * the versions of 'before' from the merge_base, HEAD, and MERGE in
+ * stages 1, 2, and 3; dst_entry will contain the respective
+ * versions of 'after' in corresponding locations. Thus, we have a
+ * total of six modes and oids, though some will be null. (Stage 0
+ * is ignored; we're interested in handling conflicts.)
+ *
+ * Since we don't turn on break-rewrites by default, neither
+ * src_entry nor dst_entry can have all three of their stages have
+ * non-null oids, meaning at most four of the six will be non-null.
+ * Also, since this is a rename, both src_entry and dst_entry will
+ * have at least one non-null oid, meaning at least two will be
+ * non-null. Of the six oids, a typical rename will have three be
+ * non-null. Only two implies a rename/delete, and four implies a
+ * rename/add.
+ */
struct stage_data *src_entry;
struct stage_data *dst_entry;
unsigned processed:1;
@@ -823,7 +842,7 @@ static int update_file_flags(struct merge_options *o,
goto update_index;
}
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf)
return err(o, _("cannot read object %s '%s'"), oid_to_hex(oid), path);
if (type != OBJ_BLOB) {
@@ -1009,8 +1028,9 @@ static int merge_file_1(struct merge_options *o,
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);
@@ -1026,10 +1046,19 @@ static int merge_file_1(struct merge_options *o,
&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");
}
@@ -1627,7 +1656,7 @@ static int read_oid_strbuf(struct merge_options *o,
void *buf;
enum object_type type;
unsigned long size;
- buf = read_sha1_file(oid->hash, &type, &size);
+ buf = read_object_file(oid, &type, &size);
if (!buf)
return err(o, _("cannot read object %s"), oid_to_hex(oid));
if (type != OBJ_BLOB) {
@@ -1952,6 +1981,13 @@ int merge_trees(struct merge_options *o,
}
if (oid_eq(&common->object.oid, &merge->object.oid)) {
+ struct strbuf sb = STRBUF_INIT;
+
+ if (!o->call_depth && index_has_changes(&sb)) {
+ err(o, _("Dirty index: cannot merge (dirty: %s)"),
+ sb.buf);
+ return 0;
+ }
output(o, 0, _("Already up to date!"));
*result = head;
return 1;
@@ -1982,10 +2018,10 @@ int merge_trees(struct merge_options *o,
get_files_dirs(o, merge);
entries = get_unmerged();
- record_df_conflict_files(o, entries);
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);
+ record_df_conflict_files(o, entries);
if (clean < 0)
goto cleanup;
for (i = entries->nr-1; 0 <= i; i--) {
@@ -2054,7 +2090,7 @@ int merge_recursive(struct merge_options *o,
{
struct commit_list *iter;
struct commit *merged_common_ancestors;
- struct tree *mrtree = mrtree;
+ struct tree *mrtree;
int clean;
if (show(o, 4)) {
@@ -2182,11 +2218,13 @@ int merge_recursive_generic(struct merge_options *o,
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))
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
return err(o, _("Unable to write index."));
return clean ? 0 : 1;