status = GIT_DELTA_UNMODIFIED;
else if (S_ISGITLINK(nmode)) {
+ int err;
git_submodule *sub;
if ((diff->opts.flags & GIT_DIFF_IGNORE_SUBMODULES) != 0)
status = GIT_DELTA_UNMODIFIED;
- else if (git_submodule_lookup(&sub, diff->repo, nitem->path) < 0)
- return -1;
- else if (git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
+ else if ((err = git_submodule_lookup(&sub, diff->repo, nitem->path)) < 0) {
+ if (err == GIT_EEXISTS)
+ status = GIT_DELTA_UNMODIFIED;
+ else
+ return err;
+ } else if (git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
status = GIT_DELTA_UNMODIFIED;
else {
unsigned int sm_status = 0;
if ((error = git_submodule_lookup(&sm, ctxt->repo, file->path)) < 0 ||
(error = git_submodule_status(&sm_status, sm)) < 0)
+ {
+ /* GIT_EEXISTS means a "submodule" that has not been git added */
+ if (error == GIT_EEXISTS)
+ error = 0;
return error;
+ }
/* update OID if we didn't have it previously */
if ((file->flags & GIT_DIFF_FLAG_VALID_OID) == 0) {
return 0;
/* detect submodules */
-
error = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path);
if (error == GIT_ENOTFOUND)
giterr_clear();
+ if (error == GIT_EEXISTS) /* if contains .git, treat as untracked submod */
+ error = 0;
+
/* if submodule, mark as GITLINK and remove trailing slash */
if (!error) {
size_t len = strlen(wi->entry.path);
if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0)
continue;
+ git_buf_truncate(&full, prefix_len);
+
if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 ||
(error = git_path_lstat(full.ptr, &ps->st)) < 0)
break;
- git_buf_truncate(&full, prefix_len);
-
if (S_ISDIR(ps->st.st_mode)) {
- ps->path[ps->path_len++] = '/';
- ps->path[ps->path_len] = '\0';
+ 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';
+ }
}
}
{ "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 },
cl_assert_equal_s(expected[idx].path, entry->path);
cl_assert_(ignored == expected[idx].ignored, expected[idx].path);
- if (!ignored && S_ISDIR(entry->mode))
+ if (!ignored &&
+ (entry->mode == GIT_FILEMODE_TREE ||
+ entry->mode == GIT_FILEMODE_COMMIT))
+ {
+ /* it is possible to advance "into" a submodule */
cl_git_pass(git_iterator_advance_into(&entry, i));
- else
+ } else
cl_git_pass(git_iterator_advance(&entry, i));
}
p_rename("submod2_target/.gitted", "submod2_target/.git");
rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+ p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
+ p_rename("submod2/not/.gitted", "submod2/not/.git");
cl_fixture_cleanup("submod2_target");
/* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
memset(&exp, 0, sizeof(exp));
+
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
- /* the following differs from "git diff 873585" by one "untracked" file
- * because the diff list includes the "not_submodule/" directory which
- * is not displayed in the text diff.
+ /* the following differs from "git diff 873585" by two "untracked" file
+ * because the diff list includes the "not" and "not-submodule" dirs which
+ * are not displayed in the text diff.
*/
- cl_assert_equal_i(10, exp.files);
+ cl_assert_equal_i(11, exp.files);
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(1, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
- cl_assert_equal_i(9, exp.file_status[GIT_DELTA_UNTRACKED]);
+ cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]);
/* the following numbers match "git diff 873585" exactly */
--- /dev/null
+ref: refs/heads/master
--- /dev/null
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
--- /dev/null
+Unnamed repository; edit this file 'description' to name the repository.
--- /dev/null
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
--- /dev/null
+0000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer <rb@github.com> 1342560358 -0700 commit (initial): Initial commit
--- /dev/null
+0000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer <rb@github.com> 1342560358 -0700 commit (initial): Initial commit
--- /dev/null
+68e92c611b80ee1ed8f38314ff9577f0d15b2444
--- /dev/null
+This is a git repo but not a submodule
--- /dev/null
+fooled you
--- /dev/null
+what am I really
+++ /dev/null
-Initial commit
+++ /dev/null
-ref: refs/heads/master
+++ /dev/null
-[core]
- repositoryformatversion = 0
- filemode = true
- bare = false
- logallrefupdates = true
- ignorecase = true
+++ /dev/null
-Unnamed repository; edit this file 'description' to name the repository.
+++ /dev/null
-# git ls-files --others --exclude-from=.git/info/exclude
-# Lines that start with '#' are comments.
-# For a project mostly in C, the following would be a good set of
-# exclude patterns (uncomment them if you want to use them):
-# *.[oa]
-# *~
+++ /dev/null
-0000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer <rb@github.com> 1342560358 -0700 commit (initial): Initial commit
+++ /dev/null
-0000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer <rb@github.com> 1342560358 -0700 commit (initial): Initial commit
+++ /dev/null
-68e92c611b80ee1ed8f38314ff9577f0d15b2444
+++ /dev/null
-This is a git repo but not a submodule
/* must create submod2_target before rewrite so prettify will work */
rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+ p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
}
void test_submodule_lookup__cleanup(void)
cl_assert(sm);
/* lookup git repo subdir that is not added as submodule */
- cl_assert(git_submodule_lookup(&sm, g_repo, "not_submodule") == GIT_EEXISTS);
+ cl_assert(git_submodule_lookup(&sm, g_repo, "not-submodule") == GIT_EEXISTS);
/* lookup existing directory that is not a submodule */
cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_dir") == GIT_ENOTFOUND);
/* must create submod2_target before rewrite so prettify will work */
rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+ p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
}
void test_submodule_modify__cleanup(void)
#include "path.h"
#include "submodule_helpers.h"
#include "fileops.h"
+#include "iterator.h"
static git_repository *g_repo = NULL;
/* must create submod2_target before rewrite so prettify will work */
rewrite_gitmodules(git_repository_workdir(g_repo));
- p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+ p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
+ p_rename("submod2/not/.gitted", "submod2/not/.git");
}
void test_submodule_status__cleanup(void)
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
- cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+ cl_assert_equal_i(GIT_ENOTFOUND,
+ git_submodule_lookup(&sm, g_repo, "just_a_dir"));
+ cl_assert_equal_i(GIT_EEXISTS,
+ git_submodule_lookup(&sm, g_repo, "not-submodule"));
+ cl_assert_equal_i(GIT_EEXISTS,
+ git_submodule_lookup(&sm, g_repo, "not"));
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
cl_git_pass(git_submodule_status(&status, sm));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
- cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+ cl_git_fail(git_submodule_lookup(&sm, g_repo, "not-submodule"));
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
cl_git_pass(git_submodule_status(&status, sm));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
- cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+ cl_assert_equal_i(GIT_ENOTFOUND,
+ git_submodule_lookup(&sm, g_repo, "just_a_dir"));
+ cl_assert_equal_i(GIT_EEXISTS,
+ git_submodule_lookup(&sm, g_repo, "not-submodule"));
+ cl_assert_equal_i(GIT_EEXISTS,
+ git_submodule_lookup(&sm, g_repo, "not"));
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
cl_git_pass(git_submodule_status(&status, sm));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
- cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+ cl_assert_equal_i(GIT_ENOTFOUND,
+ git_submodule_lookup(&sm, g_repo, "just_a_dir"));
+ cl_assert_equal_i(GIT_EEXISTS,
+ git_submodule_lookup(&sm, g_repo, "not-submodule"));
+ cl_assert_equal_i(GIT_EEXISTS,
+ git_submodule_lookup(&sm, g_repo, "not"));
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
cl_git_pass(git_submodule_status(&status, sm));
git_buf_free(&path);
}
+
+typedef struct {
+ size_t counter;
+ const char **paths;
+} submodule_expectations;
+
+static int confirm_submodule_status(
+ const char *path, unsigned int status_flags, void *payload)
+{
+ submodule_expectations *exp = payload;
+
+ while (git__suffixcmp(exp->paths[exp->counter], "/") == 0)
+ exp->counter++;
+
+ cl_assert_equal_s(exp->paths[exp->counter++], path);
+
+ GIT_UNUSED(status_flags);
+
+ return 0;
+}
+
+void test_submodule_status__iterator(void)
+{
+ git_iterator *iter;
+ const git_index_entry *entry;
+ size_t i;
+ static const char *expected[] = {
+ ".gitmodules",
+ "just_a_dir/",
+ "just_a_dir/contents",
+ "just_a_file",
+ "not",
+ "not-submodule",
+ "README.txt",
+ "sm_added_and_uncommited",
+ "sm_changed_file",
+ "sm_changed_head",
+ "sm_changed_index",
+ "sm_changed_untracked_file",
+ "sm_missing_commits",
+ "sm_unchanged",
+ NULL
+ };
+ submodule_expectations exp = { 0, expected };
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+
+ cl_git_pass(git_iterator_for_workdir(&iter, g_repo,
+ GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
+ cl_git_pass(git_iterator_current(&entry, iter));
+
+ for (i = 0; entry; ++i) {
+ cl_assert_equal_s(expected[i], entry->path);
+ cl_git_pass(git_iterator_advance(&entry, iter));
+ }
+
+ git_iterator_free(iter);
+
+ opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
+
+ cl_git_pass(git_status_foreach_ext(g_repo, &opts, confirm_submodule_status, &exp));
+}