commit 13d9040b96f5ba9ac50c137a9909f824dd5bde20 from: Stefan Sperling date: Wed Mar 27 11:33:41 2019 UTC test and improve behaviour for wt edit vs repo rm conflict commit - 085d5bcf0b7635235aeaa2608540072bdc88ae99 commit + 13d9040b96f5ba9ac50c137a9909f824dd5bde20 blob - 3421739139d8ff2c8f0b5051debfd6d9755fd579 blob + 4a33abd6b06c91758f991512a2d7475a06651970 --- lib/fileindex.c +++ lib/fileindex.c @@ -57,26 +57,29 @@ got_fileindex_entry_update(struct got_fileindex_entry { struct stat sb; - if (lstat(ondisk_path, &sb) != 0) - return got_error_from_errno(); + if (lstat(ondisk_path, &sb) != 0) { + if ((entry->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) == 0) + return got_error_from_errno(); + } else + entry->flags &= ~GOT_FILEIDX_F_NO_FILE_ON_DISK; - entry->flags &= ~GOT_FILEIDX_F_NO_FILE_ON_DISK; - - if (update_timestamps) { - entry->ctime_sec = sb.st_ctime; - entry->ctime_nsec = sb.st_ctimensec; - entry->mtime_sec = sb.st_mtime; - entry->mtime_nsec = sb.st_mtimensec; + if ((entry->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) == 0) { + if (update_timestamps) { + entry->ctime_sec = sb.st_ctime; + entry->ctime_nsec = sb.st_ctimensec; + entry->mtime_sec = sb.st_mtime; + entry->mtime_nsec = sb.st_mtimensec; + } + entry->uid = sb.st_uid; + entry->gid = sb.st_gid; + entry->size = (sb.st_size & 0xffffffff); + if (sb.st_mode & S_IFLNK) + entry->mode = GOT_FILEIDX_MODE_SYMLINK; + else + entry->mode = GOT_FILEIDX_MODE_REGULAR_FILE; + entry->mode |= ((sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) << + GOT_FILEIDX_MODE_PERMS_SHIFT); } - entry->uid = sb.st_uid; - entry->gid = sb.st_gid; - entry->size = (sb.st_size & 0xffffffff); - if (sb.st_mode & S_IFLNK) - entry->mode = GOT_FILEIDX_MODE_SYMLINK; - else - entry->mode = GOT_FILEIDX_MODE_REGULAR_FILE; - entry->mode |= ((sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) << - GOT_FILEIDX_MODE_PERMS_SHIFT); if (blob_sha1) { memcpy(entry->blob_sha1, blob_sha1, SHA1_DIGEST_LENGTH); blob - 442288387b7a34120e7bba5f27c9f45dbfc31768 blob + 3f0523ffaec3bb0f816ab6a98521fbe8d543e3f6 --- lib/worktree.c +++ lib/worktree.c @@ -844,11 +844,35 @@ done: } static const struct got_error * -install_blob(struct got_worktree *worktree, struct got_fileindex *fileindex, - struct got_fileindex_entry *entry, const char *ondisk_path, const char *path, - uint16_t te_mode, uint16_t st_mode, struct got_blob_object *blob, - int restoring_missing_file, struct got_repository *repo, - got_worktree_checkout_cb progress_cb, void *progress_arg) +update_blob_fileindex_entry(struct got_worktree *worktree, + struct got_fileindex *fileindex, struct got_fileindex_entry *ie, + const char *ondisk_path, const char *path, struct got_blob_object *blob, + int update_timestamps) +{ + const struct got_error *err = NULL; + + if (ie == NULL) + ie = got_fileindex_entry_get(fileindex, path); + if (ie) + err = got_fileindex_entry_update(ie, ondisk_path, + blob->id.sha1, worktree->base_commit_id->sha1, + update_timestamps); + else { + struct got_fileindex_entry *new_ie; + err = got_fileindex_entry_alloc(&new_ie, ondisk_path, + path, blob->id.sha1, worktree->base_commit_id->sha1); + if (!err) + err = got_fileindex_entry_add(fileindex, new_ie); + } + return err; +} + +static const struct got_error * +install_blob(struct got_worktree *worktree, const char *ondisk_path, + const char *path, uint16_t te_mode, uint16_t st_mode, + struct got_blob_object *blob, int restoring_missing_file, + struct got_repository *repo, got_worktree_checkout_cb progress_cb, + void *progress_arg) { const struct got_error *err = NULL; int fd = -1; @@ -938,18 +962,6 @@ install_blob(struct got_worktree *worktree, struct got } } - if (entry == NULL) - entry = got_fileindex_entry_get(fileindex, path); - if (entry) - err = got_fileindex_entry_update(entry, ondisk_path, - blob->id.sha1, worktree->base_commit_id->sha1, 1); - else { - err = got_fileindex_entry_alloc(&entry, ondisk_path, - path, blob->id.sha1, worktree->base_commit_id->sha1); - if (err) - goto done; - err = got_fileindex_entry_add(fileindex, entry); - } done: if (fd != -1 && close(fd) != 0 && err == NULL) err = got_error_from_errno(); @@ -1150,11 +1162,23 @@ update_blob(struct got_worktree *worktree, err = merge_blob(worktree, fileindex, ie, ondisk_path, path, te->mode, sb.st_mode, blob, repo, progress_cb, progress_arg); - else - err = install_blob(worktree, fileindex, ie, ondisk_path, path, - te->mode, sb.st_mode, blob, status == GOT_STATUS_MISSING, - repo, progress_cb, progress_arg); - + else if (status == GOT_STATUS_DELETE) { + (*progress_cb)(progress_arg, GOT_STATUS_MERGE, path); + err = update_blob_fileindex_entry(worktree, fileindex, ie, + ondisk_path, path, blob, 0); + if (err) + goto done; + } else { + err = install_blob(worktree, ondisk_path, path, te->mode, + sb.st_mode, blob, status == GOT_STATUS_MISSING, repo, + progress_cb, progress_arg); + if (err) + goto done; + err = update_blob_fileindex_entry(worktree, fileindex, ie, + ondisk_path, path, blob, 1); + if (err) + goto done; + } got_object_blob_close(blob); done: free(ondisk_path); blob - d30a87ce41088f62e2a9a1f6aa924eada9cd5d12 blob + 5b27ea3fdd42c59f652befa84aa020bb8f3b7139 --- regress/cmdline/update.sh +++ regress/cmdline/update.sh @@ -952,12 +952,73 @@ function test_update_conflict_wt_edit_vs_repo_rm { # beta is now an unversioned file... we don't flag tree conflicts yet echo '? beta' > $testroot/stdout.expected + (cd $testroot/wt && got status > $testroot/stdout) + cmp $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + +function test_update_conflict_wt_rm_vs_repo_edit { + local testroot=`test_init update_conflict_wt_rm_vs_repo_edit` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + echo "modified beta" > $testroot/repo/beta + git_commit $testroot/repo -m "modified a file" + + (cd $testroot/wt && got rm beta > /dev/null) + + (cd $testroot/wt && got update > $testroot/stdout) + + echo "G beta" > $testroot/stdout.expected + echo -n "Updated to commit " >> $testroot/stdout.expected + git_show_head $testroot/repo >> $testroot/stdout.expected + echo >> $testroot/stdout.expected + cmp $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + # beta remains a deleted file... we don't flag tree conflicts yet + echo 'D beta' > $testroot/stdout.expected (cd $testroot/wt && got status > $testroot/stdout) cmp $testroot/stdout.expected $testroot/stdout ret="$?" if [ "$ret" != "0" ]; then diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 fi + + # 'got diff' should show post-update contents of beta being deleted + local head_rev=`git_show_head $testroot/repo` + echo "diff $head_rev $testroot/wt" > $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -i | grep 'beta$' | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo 'file + /dev/null' >> $testroot/stdout.expected + echo '--- beta' >> $testroot/stdout.expected + echo '+++ beta' >> $testroot/stdout.expected + echo '@@ -1 +0,0 @@' >> $testroot/stdout.expected + echo '-modified beta' >> $testroot/stdout.expected + + (cd $testroot/wt && got diff > $testroot/stdout) + cmp $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi test_done "$testroot" "$ret" } @@ -980,3 +1041,4 @@ run_test test_update_clears_xbit run_test test_update_restores_missing_file run_test test_update_conflict_wt_add_vs_repo_add run_test test_update_conflict_wt_edit_vs_repo_rm +run_test test_update_conflict_wt_rm_vs_repo_edit