Commit 1430b4e093e8dcc1a214e26991cd06d3992db829

Stefan Sperling 2019-03-27T08:18:28

treat 'add vs add' on update as a text conflict for now

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