Commit Diff


commit - 88fb31d4fff7b0b2d49de132675aa871955ae6c4
commit + d219f183308acdda359bff4261e6ff7cd249670f
blob - 7468ff6fc6fe2ee999848cdbe8cb3db5c139cf01
blob + c1f8b7e0a389560c5e75a5dc3fe63cde1537df33
--- lib/worktree.c
+++ lib/worktree.c
@@ -916,6 +916,13 @@ done:
 	free(label_deriv);
 	return err;
 }
+
+/* forward declaration */
+static const struct got_error *
+merge_blob(int *, struct got_worktree *, struct got_blob_object *,
+    const char *, const char *, uint16_t, const char *,
+    struct got_blob_object *, struct got_object_id *,
+    struct got_repository *, got_worktree_checkout_cb, void *);
 
 /*
  * Merge a symlink into the work tree, where blob_orig acts as the common
@@ -943,6 +950,19 @@ merge_symlink(struct got_worktree *worktree,
 		return got_error_from_errno2("lstat", ondisk_path);
 
 	if (!S_ISLNK(sb.st_mode)) {
+		/*
+		 * If there is a regular file on disk, merge the symlink
+		 * target path into this file, which will usually cause
+		 * a merge conflict.
+		 */
+		if (S_ISREG(sb.st_mode)) {
+			int local_changes_subsumed;
+			return merge_blob(&local_changes_subsumed, worktree,
+			    NULL, ondisk_path, path, sb.st_mode, label_orig,
+			    blob_deriv, deriv_base_commit_id,
+			    repo, progress_cb, progress_arg);
+		}
+
 		/* TODO symlink is obstructed; do something */
 		return got_error_path(ondisk_path, GOT_ERR_FILE_OBSTRUCTED);
 	}
blob - 28666959922bc27bcad3ced40c4aed3ca140f2c0
blob + 0c33fc4f123153eadacfbd77cc65f72045a14e3b
--- regress/cmdline/cherrypick.sh
+++ regress/cmdline/cherrypick.sh
@@ -496,6 +496,7 @@ function test_cherrypick_symlink_conflicts {
 	(cd $testroot/wt && ln -sf .got/bar dotgotfoo.link)
 	# added bad symlink to file A vs added regular file A
 	echo 'this is regular file bar' > $testroot/wt/dotgotbar.link
+	(cd $testroot/wt && got add dotgotbar.link > /dev/null)
 	# removed symlink to non-existent file A vs modified symlink
 	# to nonexistent file B
 	(cd $testroot/wt && ln -sf nonexistent2 nonexistent.link)
@@ -513,14 +514,14 @@ function test_cherrypick_symlink_conflicts {
 	echo -n > $testroot/stdout.expected
 	echo "C  alpha.link" >> $testroot/stdout.expected
 	echo "C  epsilon/beta.link" >> $testroot/stdout.expected
-	echo "U  dotgotbar.link" >> $testroot/stdout.expected
+	echo "C  dotgotbar.link" >> $testroot/stdout.expected
 	echo "C  epsilon.link" >> $testroot/stdout.expected
 	echo "U  dotgotfoo.link" >> $testroot/stdout.expected
 	echo "D  nonexistent.link" >> $testroot/stdout.expected
 	echo "!  zeta.link" >> $testroot/stdout.expected
 	echo "C  new.link" >> $testroot/stdout.expected
 	echo "Merged commit $commit_id2" >> $testroot/stdout.expected
-	echo "Files with new merge conflicts: 4" >> $testroot/stdout.expected
+	echo "Files with new merge conflicts: 5" >> $testroot/stdout.expected
 	cmp -s $testroot/stdout.expected $testroot/stdout
 	ret="$?"
 	if [ "$ret" != "0" ]; then
@@ -662,7 +663,13 @@ EOF
 		test_done "$testroot" "1"
 		return 1
 	fi
-	echo -n ".got/bar" > $testroot/content.expected
+	echo "<<<<<<< merged change: commit $commit_id2" \
+		> $testroot/content.expected
+	echo -n ".got/bar" >> $testroot/content.expected
+	echo "=======" >> $testroot/content.expected
+	echo "this is regular file bar" >> $testroot/content.expected
+	echo '>>>>>>>' >> $testroot/content.expected
+	echo -n "" >> $testroot/content.expected
 	cp $testroot/wt/dotgotbar.link $testroot/content
 	cmp -s $testroot/content.expected $testroot/content
 	ret="$?"