commit aaf972e2369e5926a83162de108b6826f44e4a48 from: Omar Polo via: Thomas Adam date: Mon Sep 18 20:34:50 2023 UTC actually detect modified files when checking out with -E When checking out over a pre-existing directory tree with -E, got would store the checkout timestamp in the fileindex and so not detect local edits until those files are touch(1)ed again. Instead, detect that a file already exists during checkout and don't update its {c,m}time, leaving them to zero (the epoch), so a subsequent `got status' will look at its contents. While here, change the status char for such file from ? to E, which is what the manpage actually documents. Issue reported by naddy@ ok stsp@ commit - e7011650f26a2d1b18df28dcfb280ff8144ce08a commit + aaf972e2369e5926a83162de108b6826f44e4a48 blob - f1730de3eef8aceb312d7ffbd72f6f102611ec16 blob + 7a7742772cf995f9d64acb1ade8a8c5d7269b722 --- lib/worktree.c +++ lib/worktree.c @@ -1101,7 +1101,8 @@ done: static const struct got_error * create_fileindex_entry(struct got_fileindex_entry **new_iep, struct got_fileindex *fileindex, struct got_object_id *base_commit_id, - int wt_fd, const char *path, struct got_object_id *blob_id) + int wt_fd, const char *path, struct got_object_id *blob_id, + int update_timestamps) { const struct got_error *err = NULL; struct got_fileindex_entry *new_ie; @@ -1113,7 +1114,7 @@ create_fileindex_entry(struct got_fileindex_entry **ne return err; err = got_fileindex_entry_update(new_ie, wt_fd, path, - blob_id->sha1, base_commit_id->sha1, 1); + blob_id->sha1, base_commit_id->sha1, update_timestamps); if (err) goto done; @@ -1149,7 +1150,8 @@ install_blob(struct got_worktree *worktree, const char 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, - int path_is_unversioned, struct got_repository *repo, + int path_is_unversioned, int *update_timestamps, + struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg); /* @@ -1295,7 +1297,7 @@ install_symlink(int *is_bad_symlink, struct got_worktr return install_blob(worktree, ondisk_path, path, GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob, restoring_missing_file, reverting_versioned_file, - 1, path_is_unversioned, repo, progress_cb, + 1, path_is_unversioned, NULL, repo, progress_cb, progress_arg); } if (len > 0) { @@ -1319,7 +1321,8 @@ install_symlink(int *is_bad_symlink, struct got_worktr err = install_blob(worktree, ondisk_path, path, GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob, restoring_missing_file, reverting_versioned_file, 1, - path_is_unversioned, repo, progress_cb, progress_arg); + path_is_unversioned, NULL, repo, + progress_cb, progress_arg); return err; } @@ -1382,7 +1385,7 @@ install_symlink(int *is_bad_symlink, struct got_worktr err = install_blob(worktree, ondisk_path, path, GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob, restoring_missing_file, reverting_versioned_file, 1, - path_is_unversioned, repo, + path_is_unversioned, NULL, repo, progress_cb, progress_arg); } else if (errno == ENOTDIR) { err = got_error_path(ondisk_path, @@ -1402,7 +1405,8 @@ install_blob(struct got_worktree *worktree, const char 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, - int path_is_unversioned, struct got_repository *repo, + int path_is_unversioned, int *update_timestamps, + struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg) { const struct got_error *err = NULL; @@ -1411,6 +1415,9 @@ install_blob(struct got_worktree *worktree, const char int update = 0; char *tmppath = NULL; mode_t mode; + + if (update_timestamps) + *update_timestamps = 1; mode = get_ondisk_perms(te_mode & S_IXUSR, GOT_DEFAULT_FILE_MODE); fd = open(ondisk_path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | @@ -1435,8 +1442,10 @@ install_blob(struct got_worktree *worktree, const char ondisk_path); } else if (errno == EEXIST) { if (path_is_unversioned) { + if (update_timestamps) + *update_timestamps = 0; err = (*progress_cb)(progress_arg, - GOT_STATUS_UNVERSIONED, path); + GOT_STATUS_EXISTS, path); goto done; } if (!(S_ISLNK(st_mode) && S_ISREG(te_mode)) && @@ -1908,6 +1917,7 @@ update_blob(struct got_worktree *worktree, unsigned char status = GOT_STATUS_NO_CHANGE; struct stat sb; int fd1 = -1, fd2 = -1; + int update_timestamps; if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, path) == -1) return got_error_from_errno("asprintf"); @@ -2116,8 +2126,9 @@ update_blob(struct got_worktree *worktree, err = install_blob(worktree, ondisk_path, path, te->mode, sb.st_mode, blob, status == GOT_STATUS_MISSING, 0, 0, - status == GOT_STATUS_UNVERSIONED, repo, - progress_cb, progress_arg); + status == GOT_STATUS_UNVERSIONED, + &update_timestamps, + repo, progress_cb, progress_arg); } if (err) goto done; @@ -2129,7 +2140,7 @@ update_blob(struct got_worktree *worktree, } else { err = create_fileindex_entry(&ie, fileindex, worktree->base_commit_id, worktree->root_fd, path, - &blob->id); + &blob->id, update_timestamps); } if (err) goto done; @@ -2931,7 +2942,8 @@ add_file(struct got_worktree *worktree, struct got_fil err = install_blob(worktree, ondisk_path, path2, mode2, GOT_DEFAULT_FILE_MODE, blob2, restoring_missing_file, reverting_versioned_file, 0, - path_is_unversioned, repo, progress_cb, progress_arg); + path_is_unversioned, NULL, repo, + progress_cb, progress_arg); } if (err) return err; @@ -5286,7 +5298,7 @@ revert_file(void *arg, unsigned char status, unsigned ie->path, te ? te->mode : GOT_DEFAULT_FILE_MODE, got_fileindex_perms_to_st(ie), blob, - 0, 1, 0, 0, a->repo, + 0, 1, 0, 0, NULL, a->repo, a->progress_cb, a->progress_arg); } if (err) blob - 642aa7ff0a7ff201dae5e22b59ce99b7e725eced blob + 95f34afe31e5991bc2dfc22ad99e44cdd23832cc --- regress/cmdline/checkout.sh +++ regress/cmdline/checkout.sh @@ -489,10 +489,10 @@ test_checkout_into_nonempty_dir() { return 1 fi - 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 "E $testroot/wt/alpha" > $testroot/stdout.expected + echo "E $testroot/wt/beta" >> $testroot/stdout.expected + echo "E $testroot/wt/epsilon/zeta" >> $testroot/stdout.expected + echo "E $testroot/wt/gamma/delta" >> $testroot/stdout.expected echo "Checked out refs/heads/master: $commit_id" \ >> $testroot/stdout.expected echo "Now shut up and hack" >> $testroot/stdout.expected @@ -550,7 +550,10 @@ test_checkout_into_nonempty_dir() { return 1 fi - echo "modified alpha" > $testroot/wt/alpha + # retry, but with alpha modified + + rm -rf "$testroot/wt/.got" + echo modified alpha >$testroot/wt/alpha echo "E $testroot/wt/alpha" > $testroot/stdout.expected echo "E $testroot/wt/beta" >> $testroot/stdout.expected