commit - c90c8ce30c933a907f591ebe599ed6b7506f8217
commit + 3b9f0f87ff620ce7d6ad75195b0c67425bc96ab7
blob - fa03c453a41b27d2fc77686b381c798275eb9f9c
blob + ca0ab90afd597806d087a341444532719ec5a156
--- got/got.1
+++ got/got.1
.It \(a~ Ta versioned file is obstructed by a non-regular file
.It ! Ta a missing versioned file was restored
.It # Ta file was not updated because it contains merge conflicts
+.It ? Ta changes destined for an unversioned file were not merged
.El
.Pp
If no
blob - 437116fcd6048a862de574f7a76e6a3ae5c11309
blob + 40f832a405d94d9b628752ef3ed637eeba54faf5
--- lib/worktree.c
+++ lib/worktree.c
char *merged_path = NULL, *base_path = NULL;
int overlapcnt = 0;
char *parent;
+ char *symlink_path = NULL;
+ FILE *symlinkf = NULL;
*local_changes_subsumed = 0;
*/
}
+ /*
+ * In order the run a 3-way merge with a symlink we copy the symlink's
+ * target path into a temporary file and use that file with diff3.
+ */
+ if (S_ISLNK(st_mode)) {
+ char target_path[PATH_MAX];
+ ssize_t target_len;
+ size_t n;
+
+ free(base_path);
+ if (asprintf(&base_path, "%s/got-symlink-merge",
+ parent) == -1) {
+ err = got_error_from_errno("asprintf");
+ base_path = NULL;
+ goto done;
+ }
+ err = got_opentemp_named(&symlink_path, &symlinkf, base_path);
+ if (err)
+ goto done;
+ target_len = readlink(ondisk_path, target_path,
+ sizeof(target_path));
+ if (target_len == -1) {
+ err = got_error_from_errno2("readlink", ondisk_path);
+ goto done;
+ }
+ n = fwrite(target_path, 1, target_len, symlinkf);
+ if (n != target_len) {
+ err = got_ferror(symlinkf, GOT_ERR_IO);
+ goto done;
+ }
+ if (fflush(symlinkf) == EOF) {
+ err = got_error_from_errno2("fflush", symlink_path);
+ goto done;
+ }
+ }
+
err = got_merge_diff3(&overlapcnt, merged_fd, deriv_path,
- blob_orig_path, ondisk_path, label_deriv, label_orig, NULL);
+ blob_orig_path, symlink_path ? symlink_path : ondisk_path,
+ label_deriv, label_orig, NULL);
if (err)
goto done;
if (err) {
if (merged_path)
unlink(merged_path);
+ }
+ if (symlink_path) {
+ if (unlink(symlink_path) == -1 && err == NULL)
+ err = got_error_from_errno2("unlink", symlink_path);
}
+ if (symlinkf && fclose(symlinkf) == EOF && err == NULL)
+ err = got_error_from_errno2("fclose", symlink_path);
+ free(symlink_path);
if (merged_fd != -1 && close(merged_fd) != 0 && err == NULL)
err = got_error_from_errno("close");
if (f_orig && fclose(f_orig) != 0 && err == NULL)
const char *path, mode_t te_mode, mode_t st_mode,
struct got_blob_object *blob, int restoring_missing_file,
int reverting_versioned_file, int installing_bad_symlink,
- struct got_repository *repo,
+ int path_is_unversioned, struct got_repository *repo,
got_worktree_checkout_cb progress_cb, void *progress_arg);
/*
return install_blob(worktree, ondisk_path, path,
GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
restoring_missing_file, reverting_versioned_file,
- 1, repo, progress_cb, progress_arg);
+ 1, path_is_unversioned, repo, progress_cb,
+ progress_arg);
}
if (len > 0) {
/* Skip blob object header first time around. */
err = install_blob(worktree, ondisk_path, path,
GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
restoring_missing_file, reverting_versioned_file, 1,
- repo, progress_cb, progress_arg);
+ path_is_unversioned, repo, progress_cb, progress_arg);
goto done;
}
err = install_blob(worktree, ondisk_path, path,
GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
restoring_missing_file, reverting_versioned_file, 1,
- repo, progress_cb, progress_arg);
+ path_is_unversioned, repo, progress_cb, progress_arg);
goto done;
}
err = install_blob(worktree, ondisk_path, path,
GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
restoring_missing_file, reverting_versioned_file, 1,
- repo, progress_cb, progress_arg);
+ path_is_unversioned, repo,
+ progress_cb, progress_arg);
} else if (errno == ENOTDIR) {
err = got_error_path(ondisk_path,
GOT_ERR_FILE_OBSTRUCTED);
const char *path, mode_t te_mode, mode_t st_mode,
struct got_blob_object *blob, int restoring_missing_file,
int reverting_versioned_file, int installing_bad_symlink,
- struct got_repository *repo, got_worktree_checkout_cb progress_cb,
- void *progress_arg)
+ int path_is_unversioned, struct got_repository *repo,
+ got_worktree_checkout_cb progress_cb, void *progress_arg)
{
const struct got_error *err = NULL;
int fd = -1;
return got_error_from_errno2("open",
ondisk_path);
} else if (errno == EEXIST) {
+ if (path_is_unversioned) {
+ err = (*progress_cb)(progress_arg,
+ GOT_STATUS_UNVERSIONED, path);
+ goto done;
+ }
if (!S_ISREG(st_mode) && !installing_bad_symlink) {
/* TODO file is obstructed; do something */
err = got_error_path(ondisk_path,
} else {
err = install_blob(worktree, ondisk_path, path,
te->mode, sb.st_mode, blob,
- status == GOT_STATUS_MISSING, 0, 0, repo,
+ status == GOT_STATUS_MISSING, 0, 0,
+ status == GOT_STATUS_UNVERSIONED, repo,
progress_cb, progress_arg);
}
if (err)
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,
+ mode2, sb.st_mode, blob2, 0, 0, 0, 1, repo,
a->progress_cb, a->progress_arg);
}
if (err)
err = install_blob(a->worktree, ondisk_path,
ie->path,
te ? te->mode : GOT_DEFAULT_FILE_MODE,
- got_fileindex_perms_to_st(ie), blob, 0, 1, 0,
- a->repo, a->progress_cb, a->progress_arg);
+ got_fileindex_perms_to_st(ie), blob,
+ 0, 1, 0, 0, a->repo,
+ a->progress_cb, a->progress_arg);
}
if (err)
goto done;
blob - 3cf2adea08569d237c3ae2792cad85f134715215
blob + 4ed5d4635a5d84136d563642565378542947f5fc
--- regress/cmdline/checkout.sh
+++ regress/cmdline/checkout.sh
return 1
fi
- echo "U $testroot/wt/alpha" > $testroot/stdout.expected
- echo "U $testroot/wt/beta" >> $testroot/stdout.expected
- echo "U $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected
- echo "U $testroot/wt/gamma/delta" >> $testroot/stdout.expected
+ echo "? $testroot/wt/alpha" > $testroot/stdout.expected
+ echo "? $testroot/wt/beta" >> $testroot/stdout.expected
+ echo "? $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected
+ echo "? $testroot/wt/gamma/delta" >> $testroot/stdout.expected
echo "Now shut up and hack" >> $testroot/stdout.expected
got checkout -E $testroot/repo $testroot/wt > $testroot/stdout
blob - f9b695d8cdef6863a73038a1bdbbe643d583bb80
blob + 55663aa76dce7c64b71dc3d173d4daefb0d66870
--- regress/cmdline/cherrypick.sh
+++ regress/cmdline/cherrypick.sh
(cd $testroot/wt && ln -sfh ../gamma epsilon/beta.link)
# added regular file A vs added bad symlink to file A
(cd $testroot/wt && ln -sf .got/bar dotgotfoo.link)
+ (cd $testroot/wt && got add dotgotfoo.link > /dev/null)
# 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)
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
+ echo "C 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: 5" >> $testroot/stdout.expected
+ echo "Files with new merge conflicts: 6" >> $testroot/stdout.expected
cmp -s $testroot/stdout.expected $testroot/stdout
ret="$?"
if [ "$ret" != "0" ]; then
return 1
fi
- echo "this is regular file foo" > $testroot/content.expected
+ echo "<<<<<<< merged change: commit $commit_id2" \
+ > $testroot/content.expected
+ echo "this is regular file foo" >> $testroot/content.expected
+ echo "=======" >> $testroot/content.expected
+ echo -n ".got/bar" >> $testroot/content.expected
+ echo '>>>>>>>' >> $testroot/content.expected
cp $testroot/wt/dotgotfoo.link $testroot/content
cmp -s $testroot/content.expected $testroot/content
ret="$?"
blob - 2ee2f8f53e19a50823b280fff77f85ce353b0389
blob + 64b8fab61a492d7a1035d3082da449c5bb41d027
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
(cd $testroot/wt && ln -sfh ../gamma epsilon/beta.link)
# added regular file A vs added bad symlink to file A
(cd $testroot/wt && ln -sf .got/bar dotgotfoo.link)
+ (cd $testroot/wt && got add dotgotfoo.link > /dev/null)
# 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)
(cd $testroot/wt && got update > $testroot/stdout)
echo "C alpha.link" >> $testroot/stdout.expected
- echo "U dotgotbar.link" >> $testroot/stdout.expected
- echo "U dotgotfoo.link" >> $testroot/stdout.expected
+ echo "C dotgotbar.link" >> $testroot/stdout.expected
+ echo "C dotgotfoo.link" >> $testroot/stdout.expected
echo "C epsilon/beta.link" >> $testroot/stdout.expected
echo "C epsilon.link" >> $testroot/stdout.expected
echo "C new.link" >> $testroot/stdout.expected
echo -n "Updated to commit " >> $testroot/stdout.expected
git_show_head $testroot/repo >> $testroot/stdout.expected
echo >> $testroot/stdout.expected
- echo "Files with new merge conflicts: 5" >> $testroot/stdout.expected
+ echo "Files with new merge conflicts: 7" >> $testroot/stdout.expected
cmp -s $testroot/stdout.expected $testroot/stdout
ret="$?"
return 1
fi
- echo "this is regular file foo" > $testroot/content.expected
+ echo "<<<<<<< merged change: commit $commit_id2" \
+ > $testroot/content.expected
+ echo "this is regular file foo" >> $testroot/content.expected
+ echo "=======" >> $testroot/content.expected
+ echo -n ".got/bar" >> $testroot/content.expected
+ echo '>>>>>>>' >> $testroot/content.expected
+ echo -n "" >> $testroot/content.expected
+
cp $testroot/wt/dotgotfoo.link $testroot/content
cmp -s $testroot/content.expected $testroot/content
ret="$?"
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="$?"