Try normalizing files to avoid delete/modify conflicts when merging
If a file is modified due to normalization on one branch, and deleted on another, a merge of the two branches will result in a delete/modify conflict for that file even if it is otherwise unchanged. Try to avoid the conflict by normalizing and comparing the "base" file and the modified file when their sha1s differ. If they compare equal, the file is considered unmodified and is deleted. Signed-off-by: Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eyvind Bernhardsen committed
Jul 2, 2010 at 21:20 UTC
331a1838b26c3032bec27b66307a9de9b3b11509
2 files changed
+50
-3
merge-recursive.c
+49
-2
@@ -1056,6 +1056,53 @@ static unsigned char *stage_sha(const unsigned char *sha, unsigned mode)
1056
return (is_null_sha1(sha) || mode == 0) ? NULL: (unsigned char *)sha;
1057
}
1058
1059
+static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst)
1060
+{
1061
+ void *buf;
1062
+ enum object_type type;
1063
+ unsigned long size;
1064
+ buf = read_sha1_file(sha1, &type, &size);
1065
+ if (!buf)
1066
+ return error("cannot read object %s", sha1_to_hex(sha1));
1067
+ if (type != OBJ_BLOB) {
1068
+ free(buf);
1069
+ return error("object %s is not a blob", sha1_to_hex(sha1));
1070
+ }
1071
+ strbuf_attach(dst, buf, size, size + 1);
1072
+ return 0;
1073
+}
1074
+
1075
+static int blob_unchanged(const unsigned char *o_sha,
1076
+ const unsigned char *a_sha,
1077
+ const char *path)
1078
+{
1079
+ struct strbuf o = STRBUF_INIT;
1080
+ struct strbuf a = STRBUF_INIT;
1081
+ int ret = 0; /* assume changed for safety */
1082
+
1083
+ if (sha_eq(o_sha, a_sha))
1084
+ return 1;
1085
+ if (!merge_renormalize)
1086
+ return 0;
1087
+
1088
+ assert(o_sha && a_sha);
1089
+ if (read_sha1_strbuf(o_sha, &o) || read_sha1_strbuf(a_sha, &a))
1090
+ goto error_return;
1091
+ /*
1092
+ * Note: binary | is used so that both renormalizations are
1093
+ * performed. Comparison can be skipped if both files are
1094
+ * unchanged since their sha1s have already been compared.
1095
+ */
1096
+ if (renormalize_buffer(path, o.buf, o.len, &o) |
1097
+ renormalize_buffer(path, a.buf, o.len, &a))
1098
+ ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));
1099
+
1100
+error_return:
1101
+ strbuf_release(&o);
1102
+ strbuf_release(&a);
1103
+ return ret;
1104
+}
1105
+
1106
/* Per entry merge function */
1107
static int process_entry(struct merge_options *o,
1108
const char *path, struct stage_data *entry)
@@ -1075,8 +1122,8 @@ static int process_entry(struct merge_options *o,
1122
if (o_sha && (!a_sha || !b_sha)) {
1123
/* Case A: Deleted in one */
1124
if ((!a_sha && !b_sha) ||
1078
- (sha_eq(a_sha, o_sha) && !b_sha) ||
1079
- (!a_sha && sha_eq(b_sha, o_sha))) {
1125
+ (!b_sha && blob_unchanged(o_sha, a_sha, path)) ||
1126
+ (!a_sha && blob_unchanged(o_sha, b_sha, path))) {
1127
/* Deleted in both or deleted in one and
1128
* unchanged in the other */
1129
if (a_sha)
t/t6038-merge-text-auto.sh
+1
-1
@@ -51,7 +51,7 @@ test_expect_success 'Check merging addition of text=auto' '
51
test_cmp file file.temp
52
'
53
54
-test_expect_failure 'Test delete/normalize conflict' '
54
+test_expect_success 'Test delete/normalize conflict' '
55
git checkout side &&
56
git reset --hard initial &&
57
git rm file &&