Commit 77b699e0da3d4a4fed742893bd172f3ee7b936d5

Vicent Marti 2014-03-26T10:29:11

Merge pull request #2205 from libgit2/rb/submodule-untracked-vs-ignored Update behavior for untracked contained repositories

diff --git a/src/iterator.c b/src/iterator.c
index 401b5de..e9ec652 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1313,8 +1313,8 @@ static int workdir_iterator__update_entry(fs_iterator *fi)
 	if (error < 0)
 		giterr_clear();
 
-	/* mark submodule (or any dir with .git) as GITLINK and remove slash */
-	if (!error || error == GIT_EEXISTS) {
+	/* mark submodule as GITLINK and remove slash */
+	if (!error) {
 		fi->entry.mode = S_IFGITLINK;
 		fi->entry.path[strlen(fi->entry.path) - 1] = '\0';
 	}
diff --git a/src/path.c b/src/path.c
index fa800b7..1dccf90 100644
--- a/src/path.c
+++ b/src/path.c
@@ -1051,15 +1051,8 @@ int git_path_dirload_with_stat(
 		}
 
 		if (S_ISDIR(ps->st.st_mode)) {
-			if ((error = git_buf_joinpath(&full, full.ptr, ".git")) < 0)
-				break;
-
-			if (p_access(full.ptr, F_OK) == 0) {
-				ps->st.st_mode = GIT_FILEMODE_COMMIT;
-			} else {
-				ps->path[ps->path_len++] = '/';
-				ps->path[ps->path_len] = '\0';
-			}
+			ps->path[ps->path_len++] = '/';
+			ps->path[ps->path_len] = '\0';
 		}
 	}
 
diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c
index 92e6f72..891d8a6 100644
--- a/tests/diff/iterator.c
+++ b/tests/diff/iterator.c
@@ -737,13 +737,13 @@ void test_diff_iterator__workdir_builtin_ignores(void)
 		{ "root_test2", false },
 		{ "root_test3", false },
 		{ "root_test4.txt", false },
-		{ "sub", false },
+		{ "sub/", false },
 		{ "sub/.gitattributes", false },
 		{ "sub/abc", false },
 		{ "sub/dir/", true },
 		{ "sub/file", false },
 		{ "sub/ign/", true },
-		{ "sub/sub", false },
+		{ "sub/sub/", false },
 		{ "sub/sub/.gitattributes", false },
 		{ "sub/sub/dir", false }, /* file is not actually a dir */
 		{ "sub/sub/file", false },
diff --git a/tests/diff/submodules.c b/tests/diff/submodules.c
index da96ba9..314cf1f 100644
--- a/tests/diff/submodules.c
+++ b/tests/diff/submodules.c
@@ -1,6 +1,7 @@
 #include "clar_libgit2.h"
 #include "repository.h"
 #include "posix.h"
+#include "diff_helpers.h"
 #include "../submodule/submodule_helpers.h"
 
 static git_repository *g_repo = NULL;
@@ -11,6 +12,7 @@ void test_diff_submodules__initialize(void)
 
 void test_diff_submodules__cleanup(void)
 {
+	cl_git_sandbox_cleanup();
 }
 
 #define get_buf_ptr(buf) ((buf)->asize ? (buf)->ptr : NULL)
@@ -34,6 +36,10 @@ static void check_diff_patches_at_line(
 
 		if (expected[d] && !strcmp(expected[d], "<SKIP>"))
 			continue;
+		if (expected[d] && !strcmp(expected[d], "<UNTRACKED>")) {
+			cl_assert_at_line(delta->status == GIT_DELTA_UNTRACKED, file, line);
+			continue;
+		}
 		if (expected[d] && !strcmp(expected[d], "<END>")) {
 			cl_git_pass(git_patch_to_buf(&buf, patch));
 			cl_assert_at_line(!strcmp(expected[d], "<END>"), file, line);
@@ -115,7 +121,9 @@ void test_diff_submodules__dirty_submodule_2(void)
 	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
 	git_diff *diff = NULL, *diff2 = NULL;
 	char *smpath = "testrepo";
-	static const char *expected_none[] = { "<END>" };
+	static const char *expected_none[] = {
+		"<END>"
+	};
 	static const char *expected_dirty[] = {
 		"diff --git a/testrepo b/testrepo\nindex a65fedf..a65fedf 160000\n--- a/testrepo\n+++ b/testrepo\n@@ -1 +1 @@\n-Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750\n+Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750-dirty\n", /* testrepo.git */
 		"<END>"
@@ -170,6 +178,8 @@ void test_diff_submodules__submod2_index_to_wd(void)
 	git_diff *diff = NULL;
 	static const char *expected[] = {
 		"<SKIP>", /* .gitmodules */
+		"<UNTRACKED>", /* not-submodule */
+		"<UNTRACKED>", /* not */
 		"diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */
 		"diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */
 		"diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */
@@ -349,6 +359,8 @@ void test_diff_submodules__diff_ignore_options(void)
 	git_config *cfg;
 	static const char *expected_normal[] = {
 		"<SKIP>", /* .gitmodules */
+		"<UNTRACKED>", /* not-submodule */
+		"<UNTRACKED>", /* not */
 		"diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */
 		"diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */
 		"diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */
@@ -358,10 +370,14 @@ void test_diff_submodules__diff_ignore_options(void)
 	};
 	static const char *expected_ignore_all[] = {
 		"<SKIP>", /* .gitmodules */
+		"<UNTRACKED>", /* not-submodule */
+		"<UNTRACKED>", /* not */
 		"<END>"
 	};
 	static const char *expected_ignore_dirty[] = {
 		"<SKIP>", /* .gitmodules */
+		"<UNTRACKED>", /* not-submodule */
+		"<UNTRACKED>", /* not */
 		"diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */
 		"diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */
 		"<END>"
@@ -423,3 +439,49 @@ void test_diff_submodules__diff_ignore_options(void)
 
 	git_config_free(cfg);
 }
+
+void test_diff_submodules__skips_empty_includes_used(void)
+{
+	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+	git_diff *diff = NULL;
+	diff_expects exp;
+	git_repository *r2;
+
+	/* A side effect of of Git's handling of untracked directories and
+	 * auto-ignoring of ".git" entries is that a newly initialized Git
+	 * repo inside another repo will be skipped by diff, but one that
+	 * actually has a commit it in will show as an untracked directory.
+	 * Let's make sure that works.
+	 */
+
+	g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+	opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	memset(&exp, 0, sizeof(exp));
+	cl_git_pass(git_diff_foreach(
+		diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
+	cl_assert_equal_i(0, exp.files);
+	git_diff_free(diff);
+
+	cl_git_pass(git_repository_init(&r2, "empty_standard_repo/subrepo", 0));
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	memset(&exp, 0, sizeof(exp));
+	cl_git_pass(git_diff_foreach(
+		diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
+	cl_assert_equal_i(1, exp.files);
+	cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
+	git_diff_free(diff);
+
+	cl_git_mkfile("empty_standard_repo/subrepo/README.txt", "hello\n");
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	memset(&exp, 0, sizeof(exp));
+	cl_git_pass(git_diff_foreach(
+		diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
+	cl_assert_equal_i(1, exp.files);
+	cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
+	git_diff_free(diff);
+}
diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c
index 449dc63..6128e82 100644
--- a/tests/diff/workdir.c
+++ b/tests/diff/workdir.c
@@ -881,7 +881,7 @@ void test_diff_workdir__submodules(void)
 	 * only significant difference is that those Added items will show up
 	 * as Untracked items in the pure libgit2 diff.
 	 *
-	 * Then add in the two extra ignored items "not" and "not-submodule"
+	 * Then add in the two extra untracked items "not" and "not-submodule"
 	 * to get the 12 files reported here.
 	 */
 
@@ -890,8 +890,8 @@ void test_diff_workdir__submodules(void)
 	cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
 	cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
 	cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]);
-	cl_assert_equal_i(2, exp.file_status[GIT_DELTA_IGNORED]);
-	cl_assert_equal_i(8, exp.file_status[GIT_DELTA_UNTRACKED]);
+	cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
+	cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]);
 
 	/* the following numbers match "git diff 873585" exactly */
 
diff --git a/tests/submodule/status.c b/tests/submodule/status.c
index f5111c8..3245923 100644
--- a/tests/submodule/status.c
+++ b/tests/submodule/status.c
@@ -324,7 +324,7 @@ static int confirm_submodule_status(
 {
 	submodule_expectations *exp = payload;
 
-	while (git__suffixcmp(exp->paths[exp->counter], "/") == 0)
+	while (exp->statuses[exp->counter] < 0)
 		exp->counter++;
 
 	cl_assert_equal_i(exp->statuses[exp->counter], (int)status_flags);
@@ -345,8 +345,10 @@ void test_submodule_status__iterator(void)
 		"just_a_dir/",
 		"just_a_dir/contents",
 		"just_a_file",
-		"not",
-		"not-submodule",
+		"not-submodule/",
+		"not-submodule/README.txt",
+		"not/",
+		"not/README.txt",
 		"README.txt",
 		"sm_added_and_uncommited",
 		"sm_changed_file",
@@ -359,11 +361,13 @@ void test_submodule_status__iterator(void)
 	};
 	static int expected_flags[] = {
 		GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, /* ".gitmodules" */
-		0,					    /* "just_a_dir/" will be skipped */
+		-1,					    /* "just_a_dir/" will be skipped */
 		GIT_STATUS_CURRENT,     /* "just_a_dir/contents" */
 		GIT_STATUS_CURRENT,	    /* "just_a_file" */
-		GIT_STATUS_IGNORED,	    /* "not" (contains .git) */
-		GIT_STATUS_IGNORED,     /* "not-submodule" (contains .git) */
+		GIT_STATUS_WT_NEW,      /* "not-submodule/" untracked item */
+		-1,                     /* "not-submodule/README.txt" */
+		GIT_STATUS_WT_NEW,      /* "not/" untracked item */
+		-1,                     /* "not/README.txt" */
 		GIT_STATUS_CURRENT,     /* "README.txt */
 		GIT_STATUS_INDEX_NEW,   /* "sm_added_and_uncommited" */
 		GIT_STATUS_WT_MODIFIED, /* "sm_changed_file" */