Commit Diff


commit - 65b05cec5f251400ee165670853253a3629f4d28
commit + c90c8ce30c933a907f591ebe599ed6b7506f8217
blob - 2622e5a3f57c01d5c7c55e3ee70f1b92e04329bf
blob + fa03c453a41b27d2fc77686b381c798275eb9f9c
--- got/got.1
+++ got/got.1
@@ -1262,6 +1262,7 @@ Show the status of each affected file, using the follo
 .It d Ta file's deletion was obstructed by local modifications
 .It A Ta new file was added
 .It \(a~ Ta changes destined for a non-regular file were not merged
+.It ? Ta changes destined for an unversioned file were not merged
 .El
 .Pp
 The merged changes will appear as local changes in the work tree, which
@@ -1305,6 +1306,7 @@ Show the status of each affected file, using the follo
 .It d Ta file's deletion was obstructed by local modifications
 .It A Ta new file was added
 .It \(a~ Ta changes destined for a non-regular file were not merged
+.It ? Ta changes destined for an unversioned file were not merged
 .El
 .Pp
 The reverse-merged changes will appear as local changes in the work tree,
@@ -1380,6 +1382,7 @@ using the following status codes:
 .It d Ta file's deletion was obstructed by local modifications
 .It A Ta new file was added
 .It \(a~ Ta changes destined for a non-regular file were not merged
+.It ? Ta changes destined for an unversioned file were not merged
 .El
 .Pp
 If merge conflicts occur the rebase operation is interrupted and may
@@ -1509,6 +1512,7 @@ using the following status codes:
 .It d Ta file's deletion was obstructed by local modifications
 .It A Ta new file was added
 .It \(a~ Ta changes destined for a non-regular file were not merged
+.It ? Ta changes destined for an unversioned file were not merged
 .El
 .Pp
 If merge conflicts occur the histedit operation is interrupted and may
blob - d6fabd671ac83c50de598b8ca3a83411a51d303f
blob + 437116fcd6048a862de574f7a76e6a3ae5c11309
--- lib/worktree.c
+++ lib/worktree.c
@@ -1204,7 +1204,7 @@ static const struct got_error *
 install_symlink(int *is_bad_symlink, struct got_worktree *worktree,
     const char *ondisk_path, const char *path, struct got_blob_object *blob,
     int restoring_missing_file, int reverting_versioned_file,
-    struct got_repository *repo,
+    int path_is_unversioned, struct got_repository *repo,
     got_worktree_checkout_cb progress_cb, void *progress_arg)
 {
 	const struct got_error *err = NULL;
@@ -1307,6 +1307,11 @@ install_symlink(int *is_bad_symlink, struct got_worktr
 
 	if (symlink(target_path, ondisk_path) == -1) {
 		if (errno == EEXIST) {
+			if (path_is_unversioned) {
+				err = (*progress_cb)(progress_arg,
+				    GOT_STATUS_UNVERSIONED, path);
+				goto done;
+			}
 			err = replace_existing_symlink(ondisk_path,
 			    target_path, target_len);
 			if (err)
@@ -1790,8 +1795,10 @@ update_blob(struct got_worktree *worktree,
 			goto done;
 		if (status == GOT_STATUS_MISSING || status == GOT_STATUS_DELETE)
 			sb.st_mode = got_fileindex_perms_to_st(ie);
-	} else
+	} else {
 		sb.st_mode = GOT_DEFAULT_FILE_MODE;
+		status = GOT_STATUS_UNVERSIONED;
+	}
 
 	if (status == GOT_STATUS_OBSTRUCTED) {
 		err = (*progress_cb)(progress_arg, status, path);
@@ -1892,7 +1899,8 @@ update_blob(struct got_worktree *worktree,
 		if (S_ISLNK(te->mode)) {
 			err = install_symlink(&is_bad_symlink, worktree,
 			    ondisk_path, path, blob,
-			    status == GOT_STATUS_MISSING, 0, repo,
+			    status == GOT_STATUS_MISSING, 0,
+			    status == GOT_STATUS_UNVERSIONED, repo,
 			    progress_cb, progress_arg);
 		} else {
 			err = install_blob(worktree, ondisk_path, path,
@@ -2769,7 +2777,7 @@ merge_file_cb(void *arg, struct got_blob_object *blob1
 			if (S_ISLNK(mode2)) {
 				err = install_symlink(&is_bad_symlink,
 				    a->worktree, ondisk_path, path2, blob2, 0,
-				    0, repo, a->progress_cb, a->progress_arg);
+				    0, 1, repo, a->progress_cb, a->progress_arg);
 			} else {
 				err = install_blob(a->worktree, ondisk_path, path2,
 				    mode2, sb.st_mode, blob2, 0, 0, 0, repo,
@@ -4295,7 +4303,7 @@ revert_file(void *arg, unsigned char status, unsigned 
 			if (te && S_ISLNK(te->mode)) {
 				err = install_symlink(&is_bad_symlink,
 				    a->worktree, ondisk_path, ie->path,
-				    blob, 0, 1, a->repo,
+				    blob, 0, 1, 0, a->repo,
 				    a->progress_cb, a->progress_arg);
 			} else {
 				err = install_blob(a->worktree, ondisk_path,
@@ -5017,7 +5025,7 @@ reinstall_symlink_after_commit(int *is_bad_symlink, st
 	}
 
 	err = install_symlink(is_bad_symlink, worktree, ct->ondisk_path,
-	    ct->path, blob, 0, 0, repo, NULL, NULL);
+	    ct->path, blob, 0, 0, 0, repo, NULL, NULL);
 done:
 	if (blob)
 		got_object_blob_close(blob);
blob - 0f286697ad1b06ad111fc5219182bebfe88e1ccc
blob + f9b695d8cdef6863a73038a1bdbbe643d583bb80
--- regress/cmdline/cherrypick.sh
+++ regress/cmdline/cherrypick.sh
@@ -517,8 +517,7 @@ 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
-	# TODO: This is wrong! Unversioned file boo.link should be preserved.
-	echo "U  boo.link" >> $testroot/stdout.expected
+	echo "?  boo.link" >> $testroot/stdout.expected
 	echo "C  epsilon.link" >> $testroot/stdout.expected
 	echo "C  dotgotbar.link" >> $testroot/stdout.expected
 	echo "U  dotgotfoo.link" >> $testroot/stdout.expected
@@ -568,14 +567,13 @@ EOF
 		return 1
 	fi
 
-	# TODO: This is wrong! Unversioned file boo.link should be preserved.
-	if [ ! -h $testroot/wt/boo.link ]; then
-		echo "boo.link is not a symlink"
+	if [ -h $testroot/wt/boo.link ]; then
+		echo "boo.link is a symlink"
 		test_done "$testroot" "1"
 		return 1
 	fi
 
-	echo "beta" > $testroot/content.expected
+	echo "this is unversioned file boo" > $testroot/content.expected
 	cp $testroot/wt/boo.link $testroot/content
 	cmp -s $testroot/content.expected $testroot/content
 	ret="$?"