diff options
author | Russell Belfer <rb@github.com> | 2013-05-15 14:54:02 -0700 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-05-15 14:54:02 -0700 |
commit | dcb0f7c061554de06db5879361b22eab3517a4ee (patch) | |
tree | 2221b740034cf3bf6236daa60242bb966d7c76cd | |
parent | 55d3a39098bfc513b12ad6cb56658cb2f87e6a91 (diff) | |
download | libgit2-dcb0f7c061554de06db5879361b22eab3517a4ee.tar.gz |
Fix checkout of submodules with no .gitmodules
It is possible for there to be a submodule in a repository with
no .gitmodules file (for example, if the user forgot to commit
the .gitmodules file). In this case, core Git will just create
an empty directory as a placeholder for the submodule but
otherwise ignore it. We were generating an error and stopping
the checkout. This makes our behavior match that of core git.
-rw-r--r-- | include/git2/index.h | 2 | ||||
-rw-r--r-- | src/checkout.c | 57 | ||||
-rw-r--r-- | src/index.c | 2 |
3 files changed, 39 insertions, 22 deletions
diff --git a/include/git2/index.h b/include/git2/index.h index d23c3a8ea..bde38a9dd 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -57,6 +57,8 @@ GIT_BEGIN_DECL #define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) +#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) + /** Time used in a git index entry */ typedef struct { git_time_t seconds; diff --git a/src/checkout.c b/src/checkout.c index 4d019dbd1..5820f626a 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -820,6 +820,31 @@ static int checkout_update_index( return git_index_add(data->index, &entry); } +static int checkout_submodule_update_index( + checkout_data *data, + const git_diff_file *file) +{ + struct stat st; + + /* update the index unless prevented */ + if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0) + return 0; + + git_buf_truncate(&data->path, data->workdir_len); + if (git_buf_puts(&data->path, file->path) < 0) + return -1; + + if (p_stat(git_buf_cstr(&data->path), &st) < 0) { + giterr_set( + GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path); + return GIT_ENOTFOUND; + } + + st.st_mode = GIT_FILEMODE_COMMIT; + + return checkout_update_index(data, file, &st); +} + static int checkout_submodule( checkout_data *data, const git_diff_file *file) @@ -836,8 +861,17 @@ static int checkout_submodule( data->opts.dir_mode, GIT_MKDIR_PATH)) < 0) return error; - if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0) + if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0) { + /* I've observed repos with submodules in the tree that do not + * have a .gitmodules - core Git just makes an empty directory + */ + if (error == GIT_ENOTFOUND) { + giterr_clear(); + return checkout_submodule_update_index(data, file); + } + return error; + } /* TODO: Support checkout_strategy options. Two circumstances: * 1 - submodule already checked out, but we need to move the HEAD @@ -848,26 +882,7 @@ static int checkout_submodule( * command should probably be able to. Do we need a submodule callback? */ - /* update the index unless prevented */ - if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) { - struct stat st; - - git_buf_truncate(&data->path, data->workdir_len); - if (git_buf_puts(&data->path, file->path) < 0) - return -1; - - if ((error = p_stat(git_buf_cstr(&data->path), &st)) < 0) { - giterr_set( - GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path); - return error; - } - - st.st_mode = GIT_FILEMODE_COMMIT; - - error = checkout_update_index(data, file, &st); - } - - return error; + return checkout_submodule_update_index(data, file); } static void report_progress( diff --git a/src/index.c b/src/index.c index 53edb4874..bdbe545bf 100644 --- a/src/index.c +++ b/src/index.c @@ -106,7 +106,7 @@ static void index_entry_reuc_free(git_index_reuc_entry *reuc); GIT_INLINE(int) index_entry_stage(const git_index_entry *entry) { - return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT; + return GIT_IDXENTRY_STAGE(entry); } static int index_srch(const void *key, const void *array_member) |