Commit c856f8c503a59ab6c8cc974d467aa2fcf509fd9b

Russell Belfer 2014-03-31T12:27:05

Fix submodule sorting in workdir iterator With the changes to how git_path_dirload_with_stat handles things that look like submodules, submodules could end up sorted in the wrong order with the workdir iterator. This moves the submodule check earlier in the iterator processing of a new directory so that the submodule name updates will happen immediately and the sort order will be correct.

diff --git a/src/iterator.c b/src/iterator.c
index e9ec652..1276903 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1275,14 +1275,38 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path)
 
 static int workdir_iterator__enter_dir(fs_iterator *fi)
 {
+	fs_iterator_frame *ff = fi->stack;
+	size_t pos;
+	git_path_with_stat *entry;
+	bool found_submodules = false;
+
 	/* only push new ignores if this is not top level directory */
-	if (fi->stack->next != NULL) {
+	if (ff->next != NULL) {
 		workdir_iterator *wi = (workdir_iterator *)fi;
 		ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/');
 
 		(void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]);
 	}
 
+	/* convert submodules to GITLINK and remove trailing slashes */
+	git_vector_foreach(&ff->entries, pos, entry) {
+		if (S_ISDIR(entry->st.st_mode) &&
+			git_submodule__is_submodule(fi->base.repo, entry->path))
+		{
+			entry->st.st_mode = GIT_FILEMODE_COMMIT;
+			entry->path_len--;
+			entry->path[entry->path_len] = '\0';
+			found_submodules = true;
+		}
+	}
+
+	/* if we renamed submodules, re-sort and re-seek to start */
+	if (found_submodules) {
+		git_vector_set_sorted(&ff->entries, 0);
+		git_vector_sort(&ff->entries);
+		fs_iterator__seek_frame_start(fi, ff);
+	}
+
 	return 0;
 }
 
@@ -1295,7 +1319,6 @@ static int workdir_iterator__leave_dir(fs_iterator *fi)
 
 static int workdir_iterator__update_entry(fs_iterator *fi)
 {
-	int error = 0;
 	workdir_iterator *wi = (workdir_iterator *)fi;
 
 	/* skip over .git entries */
@@ -1305,20 +1328,6 @@ static int workdir_iterator__update_entry(fs_iterator *fi)
 	/* reset is_ignored since we haven't checked yet */
 	wi->is_ignored = -1;
 
-	/* check if apparent tree entries are actually submodules */
-	if (fi->entry.mode != GIT_FILEMODE_TREE)
-		return 0;
-
-	error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path);
-	if (error < 0)
-		giterr_clear();
-
-	/* mark submodule as GITLINK and remove slash */
-	if (!error) {
-		fi->entry.mode = S_IFGITLINK;
-		fi->entry.path[strlen(fi->entry.path) - 1] = '\0';
-	}
-
 	return 0;
 }