Commit Diff


commit - 4b0bb32784eb980751dcc4bc4cf3c8ffe40ef88d
commit + f5c49f82371af261622c0db5fea60e6558d32c6c
blob - 6e5fc2e147fc218200cc9d247d6cb75a9009faec
blob + 82b3c5fb16d76861d57253af15621fd81e41d392
--- lib/worktree.c
+++ lib/worktree.c
@@ -18,6 +18,7 @@
 #include <sys/limits.h>
 #include <sys/queue.h>
 
+#include <stddef.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -747,22 +748,29 @@ static const struct got_error *
 collect_missing_file(void *args, struct got_fileindex_entry *entry)
 {
 	struct collect_missing_entry_args *a = args;
-	char *name;
+	char *start, *end;
+	ptrdiff_t len;
 	struct got_tree_entry *te;
 	int found = 0;
 
-	if (a->path_prefix[0] == '\0' && strchr(entry->path, '/') != NULL)
-		return NULL;
 	if (a->path_prefix[0] != '\0' &&
 	    strncmp(a->path_prefix, entry->path, strlen(a->path_prefix)) != 0)
 		return NULL;
 
-	name = basename(entry->path);
-	if (name == NULL)
-		return got_error_from_errno();
+	start = entry->path + strlen(a->path_prefix);
+	while (start[0] == '/')
+		start++;
+	end = strchr(start, '/');
+	if (end == NULL) {
+		end = strchr(start, '\0');
+		if (end == NULL)
+			return got_error(GOT_ERR_BAD_PATH);
+	}
+	len = end - start;
 
 	SIMPLEQ_FOREACH(te, &a->entries->head, entry) {
-		if (strcmp(te->name, name) == 0) {
+		if (strncmp(start, te->name, len) == 0 &&
+		    te->name[len] == '\0') {
 			found = 1;
 			break;
 		}
@@ -816,6 +824,11 @@ remove_missing_files(struct got_worktree *worktree, co
 
 		if (unlink(ondisk_path) == -1)
 			err = got_error_from_errno();
+		else {
+			char *parent = dirname(ondisk_path);
+			if (rmdir(parent) == -1 && errno != ENOTEMPTY)
+				err = got_error_from_errno();
+		}
 		free(ondisk_path);
 		if (err)
 			break;
blob - 67fd42633b02f58a3db6754e107a8896d4eb1974
blob + cc23e638e0aa3f1fd81b5d6f7aae10193faec62f
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
@@ -145,6 +145,52 @@ function test_update_deletes_file {
 	test_done "$testroot" "$ret"
 }
 
+function test_update_deletes_dir {
+	local testroot=`test_init update_deletes_dir`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	if [ "$?" != "0" ]; then
+		test_done "$testroot" "$?"
+		return 1
+	fi
+
+	(cd $testroot/repo && git_rm $testroot/repo -r epsilon)
+	git_commit $testroot/repo -m "deleting a directory"
+
+	echo "D  epsilon/zeta" > $testroot/stdout.expected
+	echo -n "Updated to commit " >> $testroot/stdout.expected
+	git_show_head $testroot/repo >> $testroot/stdout.expected
+	echo >> $testroot/stdout.expected
+
+	(cd $testroot/wt && got update > $testroot/stdout)
+
+	cmp $testroot/stdout.expected $testroot/stdout
+	if [ "$?" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$?"
+		return 1
+	fi
+
+	if [ -e $testroot/wt/epsilon ]; then
+		echo "removed dir epsilon still exists on disk" >&2
+		return 1
+	fi
+
+	echo "alpha" >> $testroot/content.expected
+	echo "beta" >> $testroot/content.expected
+	echo "delta" >> $testroot/content.expected
+	cat $testroot/wt/alpha $testroot/wt/beta \
+	    $testroot/wt/gamma/delta > $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
+run_test test_update_deletes_dir