commit - 2e9bd5cb1a3122326a3b347a6febc7da047b58ad
commit + 9f32321217acc7223f02908d236a292f3fe3f2af
blob - 59440ec12abde110db7e832a12e05f5bd4bfc613
blob + c924075eacdb3d7e5ebe3fc11b3c59262e7e120f
--- got/got.1
+++ got/got.1
.It G Ta file was updated and local changes were merged cleanly
.It C Ta file was updated and conflicts occurred during merge
.It D Ta file was deleted
+.It d Ta file's deletion was prevented by local modifications
.It A Ta new file was added
.It \(a~ Ta versioned file is obstructed by a non-regular file
.It ! Ta a missing versioned file was restored
blob - 7ff73929567851b4bd0ee8ea0d46d55d776a0928
blob + 0e0b0feb644f21aef2762bad36f5c42d5dfb5591
--- lib/worktree.c
+++ lib/worktree.c
fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW |
O_CLOEXEC, mode);
if (fd == -1) {
- if (errno == ENOENT) {
+ if (errno == ENOENT || errno == ENOTDIR) {
char *parent;
err = got_path_dirname(&parent, path);
if (err)
return err;
err = add_dir_on_disk(worktree, parent);
+ if (err && err->code == GOT_ERR_FILE_OBSTRUCTED)
+ err = got_error_path(path, err->code);
free(parent);
if (err)
return err;
return NULL;
}
+static const struct got_error *remove_ondisk_file(const char *, const char *);
+
static const struct got_error *
update_blob(struct got_worktree *worktree,
struct got_fileindex *fileindex, struct got_fileindex_entry *ie,
sb.st_mode = got_fileindex_perms_to_st(ie);
} else {
if (stat(ondisk_path, &sb) == -1) {
- if (errno != ENOENT) {
+ if (errno != ENOENT && errno != ENOTDIR) {
err = got_error_from_errno2("stat",
ondisk_path);
goto done;
err = (*progress_cb)(progress_arg, GOT_STATUS_CANNOT_UPDATE,
path);
goto done;
+ }
+
+ if (S_ISDIR(te->mode)) { /* file changing into a directory */
+ if (status == GOT_STATUS_UNVERSIONED) {
+ err = (*progress_cb)(progress_arg, status, path);
+ } else if (status != GOT_STATUS_NO_CHANGE &&
+ status != GOT_STATUS_DELETE &&
+ status != GOT_STATUS_NONEXISTENT &&
+ status != GOT_STATUS_MISSING) {
+ err = (*progress_cb)(progress_arg,
+ GOT_STATUS_CANNOT_DELETE, path);
+ } else if (ie) {
+ if (status != GOT_STATUS_DELETE &&
+ status != GOT_STATUS_NONEXISTENT &&
+ status != GOT_STATUS_MISSING) {
+ err = remove_ondisk_file(worktree->root_path,
+ ie->path);
+ if (err && !(err->code == GOT_ERR_ERRNO &&
+ errno == ENOENT))
+ goto done;
+ }
+ got_fileindex_entry_remove(fileindex, ie);
+ err = (*progress_cb)(progress_arg, GOT_STATUS_DELETE,
+ ie->path);
+ }
+ goto done; /* nothing else to do */
}
if (ie && status != GOT_STATUS_MISSING && S_ISREG(sb.st_mode) &&
blob - 4aa5a095404e1e99181588149852bfe3df333a9c
blob + c2b798a572a28b05ce1a6dd4ea570a7728b1c23f
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
(cd $testroot/wt && got update > $testroot/stdout 2> $testroot/stderr)
ret=$?
if [ $ret -ne 0 ]; then
- ret="xfail change file into directory"
+ echo "update failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo "D alpha" > $testroot/stdout.expected
+ echo "A alpha/eta" >> $testroot/stdout.expected
+ echo -n "Updated to refs/heads/master: " >> $testroot/stdout.expected
+ git_show_head $testroot/repo >> $testroot/stdout.expected
+ echo >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
fi
test_done "$testroot" "$ret"
}
+test_update_changes_modified_file_to_dir() {
+ local testroot=`test_init update_changes_modified_file_to_dir`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ git_rm $testroot/repo alpha
+ mkdir $testroot/repo/alpha
+ echo eta > $testroot/repo/alpha/eta
+ (cd $testroot/repo && git add alpha/eta)
+ git_commit $testroot/repo -m "changed alpha into directory"
+
+ echo "modified alpha" >> $testroot/wt/alpha
+ cp $testroot/wt/alpha $testroot/wt/content.expected
+ (cd $testroot/wt && got update > $testroot/stdout 2> $testroot/stderr)
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ echo "update succeeded unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo "d alpha" > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "got: alpha/eta: file is obstructed" > $testroot/stderr.expected
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ fi
+ test_done "$testroot" "$ret"
+}
+
test_update_merges_file_edits() {
local testroot=`test_init update_merges_file_edits`
run_test test_update_creates_missing_parent_with_subdir
run_test test_update_file_in_subsubdir
run_test test_update_changes_file_to_dir
+run_test test_update_changes_modified_file_to_dir
run_test test_update_merges_file_edits
run_test test_update_keeps_xbit
run_test test_update_clears_xbit