preserve unversioned files when merging added symlinks
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 138 139 140 141 142
diff --git a/got/got.1 b/got/got.1
index 2622e5a..fa03c45 100644
--- a/got/got.1
+++ b/got/got.1
@@ -1262,6 +1262,7 @@ Show the status of each affected file, 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
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 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
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
diff --git a/lib/worktree.c b/lib/worktree.c
index d6fabd6..437116f 100644
--- a/lib/worktree.c
+++ b/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_worktree *worktree,
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 char staged_status,
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, struct got_commitable *ct,
}
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);
diff --git a/regress/cmdline/cherrypick.sh b/regress/cmdline/cherrypick.sh
index 0f28669..f9b695d 100755
--- a/regress/cmdline/cherrypick.sh
+++ b/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="$?"