commit - 0f58026f98fdad502497af6b7bb1e8778ee88b42
commit + c6e8a8268ec4f4240d51dcfd54d05c5370060747
blob - d3e48372f3109c8b5259a25c8bced11886caa2a1
blob + d2012785f43070b2587e5ab750848b6dbce1f336
--- lib/worktree.c
+++ lib/worktree.c
* safe location in the work tree!
*/
static const struct got_error *
-replace_existing_symlink(const char *ondisk_path, const char *target_path,
- size_t target_len)
+replace_existing_symlink(int *did_something, const char *ondisk_path,
+ const char *target_path, size_t target_len)
{
const struct got_error *err = NULL;
ssize_t elen;
char etarget[PATH_MAX];
int fd;
+ *did_something = 0;
+
/*
* "Bad" symlinks (those pointing outside the work tree or into the
* .got directory) are installed in the work tree as a regular file
return NULL; /* nothing to do */
}
+ *did_something = 1;
err = update_symlink(ondisk_path, target_path, target_len);
if (fd != -1 && close(fd) == -1 && err == NULL)
err = got_error_from_errno2("close", ondisk_path);
if (*is_bad_symlink) {
/* install as a regular file */
- *is_bad_symlink = 1;
got_object_blob_rewind(blob);
err = install_blob(worktree, ondisk_path, path,
GOT_DEFAULT_FILE_MODE, GOT_DEFAULT_FILE_MODE, blob,
if (symlink(target_path, ondisk_path) == -1) {
if (errno == EEXIST) {
+ int symlink_replaced;
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);
+ err = replace_existing_symlink(&symlink_replaced,
+ ondisk_path, target_path, target_len);
if (err)
goto done;
if (progress_cb) {
- err = (*progress_cb)(progress_arg,
- reverting_versioned_file ?
- GOT_STATUS_REVERT : GOT_STATUS_UPDATE,
- path);
+ if (symlink_replaced) {
+ err = (*progress_cb)(progress_arg,
+ reverting_versioned_file ?
+ GOT_STATUS_REVERT :
+ GOT_STATUS_UPDATE, path);
+ } else {
+ err = (*progress_cb)(progress_arg,
+ GOT_STATUS_EXISTS, path);
+ }
}
goto done; /* Nothing else to do. */
}
goto done;
}
- if (ie && status != GOT_STATUS_MISSING &&
- (te->mode & S_IXUSR) == (sb.st_mode & S_IXUSR)) {
+ if (ie && status != GOT_STATUS_MISSING && S_ISREG(sb.st_mode) &&
+ (S_ISLNK(te->mode) ||
+ (te->mode & S_IXUSR) == (sb.st_mode & S_IXUSR))) {
+ /*
+ * This is a regular file or an installed bad symlink.
+ * If the file index indicates that this file is already
+ * up-to-date with respect to the repository we can skip
+ * updating contents of this file.
+ */
if (got_fileindex_entry_has_commit(ie) &&
memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
SHA1_DIGEST_LENGTH) == 0) {
+ /* Same commit. */
err = sync_timestamps(worktree->root_fd,
path, status, ie, &sb);
if (err)
if (got_fileindex_entry_has_blob(ie) &&
memcmp(ie->blob_sha1, te->id.sha1,
SHA1_DIGEST_LENGTH) == 0) {
+ /* Different commit but the same blob. */
err = sync_timestamps(worktree->root_fd,
path, status, ie, &sb);
if (err)
blob - 2623bfe8749df2799a7d5181fce77b05f162548a
blob + c90dd13dc4e8de96ade487d14ace7bf99feecb82
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
ret="$?"
if [ "$ret" != "0" ]; then
diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
fi
+
+ # Updating an up-to-date symlink should be a no-op.
+ echo 'Already up-to-date' > $testroot/stdout.expected
+ (cd $testroot/wt && got update > $testroot/stdout)
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
test_done "$testroot" "$ret"
}