Merge pull request #4260 from libgit2/ethomson/forced_checkout_2

Update to forced checkout and untracked files
diff --git a/src/checkout.c b/src/checkout.c
index 9d1eed5..25018d2 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -370,10 +370,8 @@
 			 */
 			const git_index_entry *e = git_index_get_byindex(data->index, pos);
 
-			if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
-				notify = GIT_CHECKOUT_NOTIFY_DIRTY;
-				remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
-			}
+			if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0)
+				return git_iterator_advance_into(wditem, workdir);
 		}
 	}
 
diff --git a/src/fileops.c b/src/fileops.c
index bda17f0..2f3f58d 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -770,6 +770,9 @@
 
 		if (en == ENOENT || en == ENOTDIR) {
 			/* do nothing */
+		} else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 &&
+			en == EBUSY) {
+			error = git_path_set_error(errno, path, "rmdir");
 		} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
 			error = GIT_ITEROVER;
 		} else {
diff --git a/tests/checkout/head.c b/tests/checkout/head.c
index 07cc1d2..ded86df 100644
--- a/tests/checkout/head.c
+++ b/tests/checkout/head.c
@@ -38,7 +38,7 @@
 	cl_git_pass(git_repository_index(&index, g_repo));
 
 	p_mkdir("testrepo/newdir", 0777);
-    cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
+	cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
 
 	cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt"));
 	cl_git_pass(git_index_write(index));
@@ -60,3 +60,79 @@
 
 	git_index_free(index);
 }
+
+void test_checkout_head__do_not_remove_untracked_file(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+	cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+	cl_git_mkfile("testrepo/tracked/untracked", "untracked\n");
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+	cl_git_pass(git_index_write(index));
+
+	git_index_free(index);
+
+	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+	cl_git_pass(git_checkout_head(g_repo, &opts));
+
+	cl_assert(!git_path_isfile("testrepo/tracked/tracked"));
+	cl_assert(git_path_isfile("testrepo/tracked/untracked"));
+}
+
+void test_checkout_head__do_not_remove_untracked_file_in_subdir(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+	cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755));
+	cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+	cl_git_mkfile("testrepo/tracked/subdir/tracked", "tracked\n");
+	cl_git_mkfile("testrepo/tracked/subdir/untracked", "untracked\n");
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+	cl_git_pass(git_index_add_bypath(index, "tracked/subdir/tracked"));
+	cl_git_pass(git_index_write(index));
+
+	git_index_free(index);
+
+	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+	cl_git_pass(git_checkout_head(g_repo, &opts));
+
+	cl_assert(!git_path_isfile("testrepo/tracked/tracked"));
+	cl_assert(!git_path_isfile("testrepo/tracked/subdir/tracked"));
+	cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked"));
+}
+
+void test_checkout_head__do_remove_tracked_subdir(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_index *index;
+
+	cl_git_pass(p_mkdir("testrepo/subdir", 0755));
+	cl_git_pass(p_mkdir("testrepo/subdir/tracked", 0755));
+	cl_git_mkfile("testrepo/subdir/tracked-file", "tracked\n");
+	cl_git_mkfile("testrepo/subdir/untracked-file", "untracked\n");
+	cl_git_mkfile("testrepo/subdir/tracked/tracked1", "tracked\n");
+	cl_git_mkfile("testrepo/subdir/tracked/tracked2", "tracked\n");
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+	cl_git_pass(git_index_add_bypath(index, "subdir/tracked-file"));
+	cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked1"));
+	cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked2"));
+	cl_git_pass(git_index_write(index));
+
+	git_index_free(index);
+
+	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+	cl_git_pass(git_checkout_head(g_repo, &opts));
+
+	cl_assert(!git_path_isdir("testrepo/subdir/tracked"));
+	cl_assert(!git_path_isfile("testrepo/subdir/tracked-file"));
+	cl_assert(git_path_isfile("testrepo/subdir/untracked-file"));
+}