diff options
-rw-r--r-- | cache.h | 4 | ||||
-rw-r--r-- | path.c | 39 | ||||
-rw-r--r-- | refs/files-backend.c | 8 | ||||
-rw-r--r-- | submodule.c | 6 | ||||
-rwxr-xr-x | t/t4059-diff-submodule-not-initialized.sh | 127 |
5 files changed, 173 insertions, 11 deletions
@@ -819,8 +819,8 @@ extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...) __attribute__((format (printf, 2, 3))); extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3))); -extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path, - const char *fmt, ...) +extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path, + const char *fmt, ...) __attribute__((format (printf, 3, 4))); extern char *git_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); @@ -6,6 +6,7 @@ #include "string-list.h" #include "dir.h" #include "worktree.h" +#include "submodule-config.h" static int get_st_mode_bits(const char *path, int *mode) { @@ -466,12 +467,16 @@ const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...) return pathname->buf; } -static void do_submodule_path(struct strbuf *buf, const char *path, - const char *fmt, va_list args) +/* Returns 0 on success, negative on failure. */ +#define SUBMODULE_PATH_ERR_NOT_CONFIGURED -1 +static int do_submodule_path(struct strbuf *buf, const char *path, + const char *fmt, va_list args) { const char *git_dir; struct strbuf git_submodule_common_dir = STRBUF_INIT; struct strbuf git_submodule_dir = STRBUF_INIT; + const struct submodule *sub; + int err = 0; strbuf_addstr(buf, path); strbuf_complete(buf, '/'); @@ -482,6 +487,17 @@ static void do_submodule_path(struct strbuf *buf, const char *path, strbuf_reset(buf); strbuf_addstr(buf, git_dir); } + if (!is_git_directory(buf->buf)) { + gitmodules_config(); + sub = submodule_from_path(null_sha1, path); + if (!sub) { + err = SUBMODULE_PATH_ERR_NOT_CONFIGURED; + goto cleanup; + } + strbuf_reset(buf); + strbuf_git_path(buf, "%s/%s", "modules", sub->name); + } + strbuf_addch(buf, '/'); strbuf_addbuf(&git_submodule_dir, buf); @@ -492,27 +508,38 @@ static void do_submodule_path(struct strbuf *buf, const char *path, strbuf_cleanup_path(buf); +cleanup: strbuf_release(&git_submodule_dir); strbuf_release(&git_submodule_common_dir); + + return err; } char *git_pathdup_submodule(const char *path, const char *fmt, ...) { + int err; va_list args; struct strbuf buf = STRBUF_INIT; va_start(args, fmt); - do_submodule_path(&buf, path, fmt, args); + err = do_submodule_path(&buf, path, fmt, args); va_end(args); + if (err) { + strbuf_release(&buf); + return NULL; + } return strbuf_detach(&buf, NULL); } -void strbuf_git_path_submodule(struct strbuf *buf, const char *path, - const char *fmt, ...) +int strbuf_git_path_submodule(struct strbuf *buf, const char *path, + const char *fmt, ...) { + int err; va_list args; va_start(args, fmt); - do_submodule_path(buf, path, fmt, args); + err = do_submodule_path(buf, path, fmt, args); va_end(args); + + return err; } static void do_git_common_path(struct strbuf *buf, diff --git a/refs/files-backend.c b/refs/files-backend.c index 12290d24964..1f34b444af8 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1225,13 +1225,19 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir) struct strbuf refname; struct strbuf path = STRBUF_INIT; size_t path_baselen; + int err = 0; if (*refs->name) - strbuf_git_path_submodule(&path, refs->name, "%s", dirname); + err = strbuf_git_path_submodule(&path, refs->name, "%s", dirname); else strbuf_git_path(&path, "%s", dirname); path_baselen = path.len; + if (err) { + strbuf_release(&path); + return; + } + d = opendir(path.buf); if (!d) { strbuf_release(&path); diff --git a/submodule.c b/submodule.c index 1b5cdfb7e78..6096cf428be 100644 --- a/submodule.c +++ b/submodule.c @@ -127,7 +127,9 @@ static int add_submodule_odb(const char *path) int ret = 0; size_t alloc; - strbuf_git_path_submodule(&objects_directory, path, "objects/"); + ret = strbuf_git_path_submodule(&objects_directory, path, "objects/"); + if (ret) + goto done; if (!is_directory(objects_directory.buf)) { ret = -1; goto done; @@ -348,7 +350,7 @@ void show_submodule_summary(FILE *f, const char *path, if (is_null_sha1(two)) message = "(submodule deleted)"; else if (add_submodule_odb(path)) - message = "(not checked out)"; + message = "(not initialized)"; else if (is_null_sha1(one)) message = "(new submodule)"; else if (!(left = lookup_commit_reference(one)) || diff --git a/t/t4059-diff-submodule-not-initialized.sh b/t/t4059-diff-submodule-not-initialized.sh new file mode 100755 index 00000000000..cd70fd5192e --- /dev/null +++ b/t/t4059-diff-submodule-not-initialized.sh @@ -0,0 +1,127 @@ +#!/bin/sh +# +# Copyright (c) 2016 Jacob Keller, based on t4041 by Jens Lehmann +# + +test_description='Test for submodule diff on non-checked out submodule + +This test tries to verify that add_submodule_odb works when the submodule was +initialized previously but the checkout has since been removed. +' + +. ./test-lib.sh + +# Tested non-UTF-8 encoding +test_encoding="ISO8859-1" + +# String "added" in German (translated with Google Translate), encoded in UTF-8, +# used in sample commit log messages in add_file() function below. +added=$(printf "hinzugef\303\274gt") + +add_file () { + ( + cd "$1" && + shift && + for name + do + echo "$name" >"$name" && + git add "$name" && + test_tick && + # "git commit -m" would break MinGW, as Windows refuse to pass + # $test_encoding encoded parameter to git. + echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding | + git -c "i18n.commitEncoding=$test_encoding" commit -F - + done >/dev/null && + git rev-parse --short --verify HEAD + ) +} + +commit_file () { + test_tick && + git commit "$@" -m "Commit $*" >/dev/null +} + +test_expect_success 'setup - submodules' ' + test_create_repo sm2 && + add_file . foo && + add_file sm2 foo1 foo2 && + smhead1=$(git -C sm2 rev-parse --short --verify HEAD) +' + +test_expect_success 'setup - git submodule add' ' + git submodule add ./sm2 sm1 && + commit_file sm1 .gitmodules && + git diff-tree -p --no-commit-id --submodule=log HEAD -- sm1 >actual && + cat >expected <<-EOF && + Submodule sm1 0000000...$smhead1 (new submodule) + EOF + test_cmp expected actual +' + +test_expect_success 'submodule directory removed' ' + rm -rf sm1 && + git diff-tree -p --no-commit-id --submodule=log HEAD -- sm1 >actual && + cat >expected <<-EOF && + Submodule sm1 0000000...$smhead1 (new submodule) + EOF + test_cmp expected actual +' + +test_expect_success 'setup - submodule multiple commits' ' + git submodule update --checkout sm1 && + smhead2=$(add_file sm1 foo3 foo4) && + commit_file sm1 && + git diff-tree -p --no-commit-id --submodule=log HEAD >actual && + cat >expected <<-EOF && + Submodule sm1 $smhead1..$smhead2: + > Add foo4 ($added foo4) + > Add foo3 ($added foo3) + EOF + test_cmp expected actual +' + +test_expect_success 'submodule removed multiple commits' ' + rm -rf sm1 && + git diff-tree -p --no-commit-id --submodule=log HEAD >actual && + cat >expected <<-EOF && + Submodule sm1 $smhead1..$smhead2: + > Add foo4 ($added foo4) + > Add foo3 ($added foo3) + EOF + test_cmp expected actual +' + +test_expect_success 'submodule not initialized in new clone' ' + git clone . sm3 && + git -C sm3 diff-tree -p --no-commit-id --submodule=log HEAD >actual && + cat >expected <<-EOF && + Submodule sm1 $smhead1...$smhead2 (not initialized) + EOF + test_cmp expected actual +' + +test_expect_success 'setup submodule moved' ' + git submodule update --checkout sm1 && + git mv sm1 sm4 && + commit_file sm4 && + git diff-tree -p --no-commit-id --submodule=log HEAD >actual && + cat >expected <<-EOF && + Submodule sm4 0000000...$smhead2 (new submodule) + EOF + test_cmp expected actual +' + +test_expect_success 'submodule moved then removed' ' + smhead3=$(add_file sm4 foo6 foo7) && + commit_file sm4 && + rm -rf sm4 && + git diff-tree -p --no-commit-id --submodule=log HEAD >actual && + cat >expected <<-EOF && + Submodule sm4 $smhead2..$smhead3: + > Add foo7 ($added foo7) + > Add foo6 ($added foo6) + EOF + test_cmp expected actual +' + +test_done |