Merge pull request #3303 from libgit2/cmn/index-add-submodule Allow adding a submodule through git_index_add_bypath
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
diff --git a/include/git2/errors.h b/include/git2/errors.h
index a81aa05..e189e55 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -48,6 +48,7 @@ typedef enum {
GIT_EEOF = -20, /**< Unexpected EOF */
GIT_EINVALID = -21, /**< Invalid operation or input */
GIT_EUNCOMMITTED = -22, /**< Uncommitted changes in index prevented operation */
+ GIT_EDIRECTORY = -23, /**< The operation is not valid for a directory */
GIT_PASSTHROUGH = -30, /**< Internal only */
GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */
diff --git a/src/blob.c b/src/blob.c
index 07c4d92..ad0f4ac 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -185,6 +185,12 @@ int git_blob__create_from_paths(
(error = git_repository_odb(&odb, repo)) < 0)
goto done;
+ if (S_ISDIR(st.st_mode)) {
+ giterr_set(GITERR_ODB, "cannot create blob from '%s'; it is a directory", content_path);
+ error = GIT_EDIRECTORY;
+ goto done;
+ }
+
if (out_st)
memcpy(out_st, &st, sizeof(st));
diff --git a/src/index.c b/src/index.c
index 5ce5522..501498e 100644
--- a/src/index.c
+++ b/src/index.c
@@ -1236,9 +1236,29 @@ int git_index_add_bypath(git_index *index, const char *path)
assert(index && path);
- if ((ret = index_entry_init(&entry, index, path)) < 0 ||
- (ret = index_insert(index, &entry, 1, false)) < 0)
+ if ((ret = index_entry_init(&entry, index, path)) == 0)
+ ret = index_insert(index, &entry, 1, false);
+
+ /* If we were given a directory, let's see if it's a submodule */
+ if (ret < 0 && ret != GIT_EDIRECTORY)
+ return ret;
+
+ if (ret == GIT_EDIRECTORY) {
+ git_submodule *sm;
+ git_error_state err;
+
+ giterr_capture(&err, ret);
+
+ ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
+ if (ret == GIT_ENOTFOUND)
+ return giterr_restore(&err);
+ else
+ git__free(err.error_msg.message);
+
+ ret = git_submodule_add_to_index(sm, false);
+ git_submodule_free(sm);
return ret;
+ }
/* Adding implies conflict was resolved, move conflict entries to REUC */
if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
diff --git a/tests/index/bypath.c b/tests/index/bypath.c
new file mode 100644
index 0000000..ddb766a
--- /dev/null
+++ b/tests/index/bypath.c
@@ -0,0 +1,35 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "../submodule/submodule_helpers.h"
+
+static git_repository *g_repo;
+static git_index *g_idx;
+
+void test_index_bypath__initialize(void)
+{
+ g_repo = setup_fixture_submod2();
+ cl_git_pass(git_repository_index__weakptr(&g_idx, g_repo));
+}
+
+void test_index_bypath__cleanup(void)
+{
+ g_repo = NULL;
+ g_idx = NULL;
+}
+
+void test_index_bypath__add_directory(void)
+{
+ cl_git_fail_with(GIT_EDIRECTORY, git_index_add_bypath(g_idx, "just_a_dir"));
+}
+
+void test_index_bypath__add_submodule(void)
+{
+ unsigned int status;
+ const char *sm_name = "sm_changed_head";
+
+ cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
+ cl_assert_equal_i(GIT_SUBMODULE_STATUS_WD_MODIFIED, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
+ cl_git_pass(git_index_add_bypath(g_idx, sm_name));
+ cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
+ cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
+}
diff --git a/tests/submodule/add.c b/tests/submodule/add.c
index 01625d3..c3b3e63 100644
--- a/tests/submodule/add.c
+++ b/tests/submodule/add.c
@@ -4,6 +4,7 @@
#include "submodule_helpers.h"
#include "config/config_helpers.h"
#include "fileops.h"
+#include "repository.h"
static git_repository *g_repo = NULL;