Commit Diff


commit - e60e7f5bf0d3d27834b9712529836b42207853c8
commit + a378724ff7c52fed47ca10ec7bb827ad4955ce57
blob - 914b39fda8d355979f18027abf6b0d7b7091aa65
blob + 1ce550db674eb7b48feb8bd5c8e48a2ed6f537c6
--- got/got.1
+++ got/got.1
@@ -105,6 +105,7 @@ Show the status of each affected file, using the follo
 .It D Ta file was deleted
 .It A Ta new file was added
 .It ~ Ta versioned file is obstructed by a non-regular file
+.It ! Ta a missing versioned file was restored
 .El
 .Pp
 If the
blob - 755f467c2aa1a389cc6240409b367803b91565a5
blob + 709848c071063737c6e2c461124cc38e2ec0eac9
--- got/got.c
+++ got/got.c
@@ -436,7 +436,8 @@ update_progress(void *arg, unsigned char status, const
 	if (status == GOT_STATUS_EXISTS)
 		return;
 
-	*did_something = 1;
+	if (status != GOT_STATUS_MISSING)
+		*did_something = 1;
 	while (path[0] == '/')
 		path++;
 	printf("%c  %s\n", status, path);
blob - f8449d38ccd31e85697d762976525f415268ccb9
blob + 893ba6cf0e45a7e3252f09fe1a4bfe287009aba3
--- lib/worktree.c
+++ lib/worktree.c
@@ -697,7 +697,7 @@ 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 mode, struct got_blob_object *blob,
+   uint16_t mode, struct got_blob_object *blob, int restoring_missing_file,
    struct got_repository *repo, got_worktree_checkout_cb progress_cb,
    void *progress_arg)
 {
@@ -742,8 +742,11 @@ install_blob(struct got_worktree *worktree, struct got
 			return got_error_from_errno();
 	}
 
-	(*progress_cb)(progress_arg,
-	    update ? GOT_STATUS_UPDATE : GOT_STATUS_ADD, path);
+	if (restoring_missing_file)
+		(*progress_cb)(progress_arg, GOT_STATUS_MISSING, path);
+	else
+		(*progress_cb)(progress_arg,
+		    update ? GOT_STATUS_UPDATE : GOT_STATUS_ADD, path);
 
 	hdrlen = got_object_blob_get_hdrlen(blob);
 	do {
@@ -826,8 +829,13 @@ get_file_status(unsigned char *status, struct got_file
 
 	*status = GOT_STATUS_NO_CHANGE;
 
-	if (lstat(abspath, &sb) == -1)
+	if (lstat(abspath, &sb) == -1) {
+		if (errno == ENOENT) {
+			*status = GOT_STATUS_MISSING;
+			return NULL;
+		}
 		return got_error_from_errno();
+	}
 
 	if (!S_ISREG(sb.st_mode)) {
 		*status = GOT_STATUS_OBSTRUCTED;
@@ -903,16 +911,6 @@ update_blob(struct got_worktree *worktree,
 		return got_error_from_errno();
 
 	if (ie) {
-		if (memcmp(ie->commit_sha1, worktree->base_commit_id->sha1,
-		    SHA1_DIGEST_LENGTH) == 0) {
-			(*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
-			    path);
-			goto done;
-		}
-		if (memcmp(ie->blob_sha1,
-		    te->id->sha1, SHA1_DIGEST_LENGTH) == 0)
-			goto done;
-
 		err = get_file_status(&status, ie, ondisk_path, repo);
 		if (err)
 			goto done;
@@ -920,6 +918,19 @@ update_blob(struct got_worktree *worktree,
 		if (status == GOT_STATUS_OBSTRUCTED) {
 			(*progress_cb)(progress_arg, status, path);
 			goto done;
+		}
+
+		if (status == GOT_STATUS_NO_CHANGE) {
+			if (memcmp(ie->commit_sha1,
+			    worktree->base_commit_id->sha1,
+			    SHA1_DIGEST_LENGTH) == 0) {
+				(*progress_cb)(progress_arg, GOT_STATUS_EXISTS,
+				    path);
+				goto done;
+			}
+			if (memcmp(ie->blob_sha1,
+			    te->id->sha1, SHA1_DIGEST_LENGTH) == 0)
+				goto done;
 		}
 	}
 
@@ -932,7 +943,8 @@ update_blob(struct got_worktree *worktree,
 		    te->mode, blob, repo, progress_cb, progress_arg);
 	else
 		err = install_blob(worktree, fileindex, ie, ondisk_path, path,
-		    te->mode, blob, repo, progress_cb, progress_arg);
+		    te->mode, blob, status == GOT_STATUS_MISSING, repo,
+		    progress_cb, progress_arg);
 
 	got_object_blob_close(blob);
 done:
blob - e7ae6c144216594739f0afb77723057f5bf22b17
blob + 3267b8ed203708fea01289cbeae3ed1131275e5e
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
@@ -809,7 +809,43 @@ function test_update_clears_xbit {
 	fi
 	test_done "$testroot" "$ret"
 }
+
+function test_update_restores_missing_file {
+	local testroot=`test_init update_restores_missing_file`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
 
+	rm $testroot/wt/alpha
+
+	echo "!  alpha" > $testroot/stdout.expected
+	echo "Already up-to-date" >> $testroot/stdout.expected
+	(cd $testroot/wt && got update > $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
+
+	echo "alpha" > $testroot/content.expected
+
+	cat $testroot/wt/alpha > $testroot/content
+
+	cmp $testroot/content.expected $testroot/content
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/content.expected $testroot/content
+	fi
+	test_done "$testroot" "$ret"
+}
+
 run_test test_update_basic
 run_test test_update_adds_file
 run_test test_update_deletes_file
@@ -826,3 +862,4 @@ run_test test_update_file_in_subsubdir
 run_test test_update_merges_file_edits
 run_test test_update_keeps_xbit
 run_test test_update_clears_xbit
+run_test test_update_restores_missing_file