treat 'add vs add' on update as a text conflict for now
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
diff --git a/lib/worktree.c b/lib/worktree.c
index c7e43f2..cd22378 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -714,7 +714,6 @@ merge_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
FILE *f1 = NULL, *f2 = NULL;
char *blob1_path = NULL, *blob2_path = NULL;
char *merged_path = NULL, *base_path = NULL;
- struct got_object_id id2;
char *id_str = NULL;
char *label1 = NULL;
int overlapcnt = 0, update_timestamps = 0;
@@ -755,14 +754,22 @@ merge_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
err = got_opentemp_named(&blob2_path, &f2, base_path);
if (err)
goto done;
-
- memcpy(id2.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
- err = got_object_open_as_blob(&blob2, repo, &id2, 8192);
- if (err)
- goto done;
- err = got_object_blob_dump_to_file(NULL, NULL, f2, blob2);
- if (err)
- goto done;
+ if (got_fileindex_entry_has_blob(ie)) {
+ struct got_object_id id2;
+ memcpy(id2.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
+ err = got_object_open_as_blob(&blob2, repo, &id2, 8192);
+ if (err)
+ goto done;
+ err = got_object_blob_dump_to_file(NULL, NULL, f2, blob2);
+ if (err)
+ goto done;
+ } else {
+ /*
+ * If the file has no blob, this is an "add vs add" conflict,
+ * and we simply use an empty ancestor file to make both files
+ * appear in the merged result in their entirety.
+ */
+ }
err = got_object_id_str(&id_str, worktree->base_commit_id);
if (err)
@@ -1081,14 +1088,16 @@ update_blob(struct got_worktree *worktree,
}
if (ie && status != GOT_STATUS_MISSING) {
- if (memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
+ if (got_fileindex_entry_has_commit(ie) &&
+ memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
SHA1_DIGEST_LENGTH) == 0) {
(*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
path);
goto done;
}
- if (memcmp(ie->blob_sha1,
- te->id->sha1, SHA1_DIGEST_LENGTH) == 0)
+ if (got_fileindex_entry_has_blob(ie) &&
+ memcmp(ie->blob_sha1, te->id->sha1,
+ SHA1_DIGEST_LENGTH) == 0)
goto done;
}
@@ -1096,7 +1105,7 @@ update_blob(struct got_worktree *worktree,
if (err)
goto done;
- if (status == GOT_STATUS_MODIFY)
+ if (status == GOT_STATUS_MODIFY || status == GOT_STATUS_ADD)
err = merge_blob(worktree, fileindex, ie, ondisk_path, path,
te->mode, sb.st_mode, blob, repo, progress_cb,
progress_arg);
diff --git a/regress/cmdline/update.sh b/regress/cmdline/update.sh
index f950162..897edc3 100755
--- a/regress/cmdline/update.sh
+++ b/regress/cmdline/update.sh
@@ -848,6 +848,55 @@ function test_update_restores_missing_file {
test_done "$testroot" "$ret"
}
+function test_update_conflict_add_vs_add {
+ local testroot=`test_init update_conflict_add_vs_add`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "new" > $testroot/repo/gamma/new
+ (cd $testroot/repo && git add .)
+ git_commit $testroot/repo -m "adding a new file"
+
+ echo "also new" > $testroot/wt/gamma/new
+ (cd $testroot/wt && got add gamma/new >/dev/null)
+
+ (cd $testroot/wt && got update > $testroot/stdout)
+
+ echo "C gamma/new" > $testroot/stdout.expected
+ echo -n "Updated to commit " >> $testroot/stdout.expected
+ git_show_head $testroot/repo >> $testroot/stdout.expected
+ echo >> $testroot/stdout.expected
+ cmp $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n "<<<<<<< commit " > $testroot/content.expected
+ git_show_head $testroot/repo >> $testroot/content.expected
+ echo >> $testroot/content.expected
+ echo "new" >> $testroot/content.expected
+ echo "=======" >> $testroot/content.expected
+ echo "also new" >> $testroot/content.expected
+ echo '>>>>>>> gamma/new' >> $testroot/content.expected
+
+ cat $testroot/wt/gamma/new > $testroot/content
+
+ cmp $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_update_basic
run_test test_update_adds_file
run_test test_update_deletes_file
@@ -865,3 +914,4 @@ run_test test_update_merges_file_edits
run_test test_update_keeps_xbit
run_test test_update_clears_xbit
run_test test_update_restores_missing_file
+run_test test_update_conflict_add_vs_add