summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/submodule.c50
-rw-r--r--tests/submodule/nosubs.c67
2 files changed, 107 insertions, 10 deletions
diff --git a/src/submodule.c b/src/submodule.c
index 5061cadc6..913c97a87 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -1345,8 +1345,9 @@ static int submodule_load_from_config(
const git_config_entry *entry, void *payload)
{
git_submodule_cache *cache = payload;
- const char *namestart, *property, *alternate = NULL;
+ const char *namestart, *property;
const char *key = entry->name, *value = entry->value, *path;
+ char *alternate = NULL, *replaced = NULL;
git_buf name = GIT_BUF_INIT;
git_submodule *sm = NULL;
int error = 0;
@@ -1377,17 +1378,39 @@ static int submodule_load_from_config(
* should be strcasecmp
*/
- if (strcmp(sm->name, name.ptr) != 0) {
- alternate = sm->name = git_buf_detach(&name);
- } else if (path && strcmp(path, sm->path) != 0) {
- alternate = sm->path = git__strdup(value);
- if (!sm->path) {
- error = -1;
- goto done;
+ if (strcmp(sm->name, name.ptr) != 0) { /* name changed */
+ if (!strcmp(sm->path, name.ptr)) { /* already set as path */
+ replaced = sm->name;
+ sm->name = sm->path;
+ } else {
+ if (sm->name != sm->path)
+ replaced = sm->name;
+ alternate = sm->name = git_buf_detach(&name);
+ }
+ }
+ else if (path && strcmp(path, sm->path) != 0) { /* path changed */
+ if (!strcmp(sm->name, value)) { /* already set as name */
+ replaced = sm->path;
+ sm->path = sm->name;
+ } else {
+ if (sm->path != sm->name)
+ replaced = sm->path;
+ if ((alternate = git__strdup(value)) == NULL) {
+ error = -1;
+ goto done;
+ }
+ sm->path = alternate;
}
}
- /* Found a alternate key for the submodule */
+ /* Deregister under name being replaced */
+ if (replaced) {
+ git_strmap_delete(cache->submodules, replaced);
+ git_submodule_free(sm);
+ git__free(replaced);
+ }
+
+ /* Insert under alternate key */
if (alternate) {
void *old_sm = NULL;
git_strmap_insert2(cache->submodules, alternate, sm, old_sm, error);
@@ -1684,6 +1707,8 @@ static int submodule_cache_refresh(git_submodule_cache *cache, int refresh)
GIT_SUBMODULE_STATUS__WD_SCANNED |
GIT_SUBMODULE_STATUS__WD_FLAGS |
GIT_SUBMODULE_STATUS__WD_OID_VALID;
+ else
+ goto cleanup; /* nothing to do */
submodule_cache_clear_flags(cache, mask);
@@ -1726,7 +1751,12 @@ static int submodule_cache_refresh(git_submodule_cache *cache, int refresh)
/* remove submodules that no longer exist */
git_strmap_foreach_value(cache->submodules, sm, {
- if (sm && (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS) == 0)
+ /* purge unless in HEAD, index, or .gitmodules; no sm for wd only */
+ if (sm != NULL &&
+ !(sm->flags &
+ (GIT_SUBMODULE_STATUS_IN_HEAD |
+ GIT_SUBMODULE_STATUS_IN_INDEX |
+ GIT_SUBMODULE_STATUS_IN_CONFIG)))
submodule_cache_remove_item(cache, sm, true);
});
diff --git a/tests/submodule/nosubs.c b/tests/submodule/nosubs.c
index 5ef4f42ab..cabb53ead 100644
--- a/tests/submodule/nosubs.c
+++ b/tests/submodule/nosubs.c
@@ -2,6 +2,7 @@
#include "clar_libgit2.h"
#include "posix.h"
+#include "fileops.h"
void test_submodule_nosubs__cleanup(void)
{
@@ -93,3 +94,69 @@ void test_submodule_nosubs__bad_gitmodules(void)
cl_git_pass(git_submodule_lookup(NULL, repo, "foobar"));
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(NULL, repo, "subdir"));
}
+
+void test_submodule_nosubs__add_and_delete(void)
+{
+ git_repository *repo = cl_git_sandbox_init("status");
+ git_submodule *sm;
+ git_buf buf = GIT_BUF_INIT;
+
+ /* note the lack of calls to git_submodule_reload - this *should* work */
+
+ cl_git_fail(git_submodule_lookup(NULL, repo, "libgit2"));
+ cl_git_fail(git_submodule_lookup(NULL, repo, "submodules/libgit2"));
+
+ /* create */
+
+ cl_git_pass(git_submodule_add_setup(
+ &sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
+ cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
+ cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
+ git_submodule_free(sm);
+
+ cl_git_pass(git_futils_readbuffer(&buf, "status/.gitmodules"));
+ cl_assert(strstr(buf.ptr, "[submodule \"submodules/libgit2\"]") != NULL);
+ cl_assert(strstr(buf.ptr, "path = submodules/libgit2") != NULL);
+ git_buf_free(&buf);
+
+ /* lookup */
+
+ cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
+ cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
+ cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
+ cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
+ git_submodule_free(sm);
+
+ /* update name */
+
+ cl_git_rewritefile(
+ "status/.gitmodules",
+ "[submodule \"libgit2\"]\n"
+ " path = submodules/libgit2\n"
+ " url = https://github.com/libgit2/libgit2.git\n");
+
+ cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2"));
+ cl_assert_equal_s("libgit2", git_submodule_name(sm));
+ cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
+ git_submodule_free(sm);
+ cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
+ git_submodule_free(sm);
+
+ /* revert name update */
+
+ cl_git_rewritefile(
+ "status/.gitmodules",
+ "[submodule \"submodules/libgit2\"]\n"
+ " path = submodules/libgit2\n"
+ " url = https://github.com/libgit2/libgit2.git\n");
+
+ cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
+ cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
+ git_submodule_free(sm);
+
+ /* remove completely */
+
+ cl_must_pass(p_unlink("status/.gitmodules"));
+ cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
+ cl_git_fail(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
+}