diff --git a/Documentation/config.txt b/Documentation/config.txt index 73904bce55..989eb80ac1 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1607,6 +1607,10 @@ imap:: The configuration variables in the 'imap' section are described in linkgit:git-imap-send[1]. +index.version:: + Specify the version with which new index files should be + initialized. This does not affect existing repositories. + init.templatedir:: Specify the directory from which templates will be copied. (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].) diff --git a/Documentation/git.txt b/Documentation/git.txt index 02bbc084b8..27a199ca1a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -720,6 +720,11 @@ Git so take care if using Cogito etc. index file. If not specified, the default of `$GIT_DIR/index` is used. +'GIT_INDEX_VERSION':: + This environment variable allows the specification of an index + version for new repositories. It won't affect existing index + files. By default index file version [23] is used. + 'GIT_OBJECT_DIRECTORY':: If the object storage directory is specified via this environment variable then the sha1 directories are created diff --git a/Makefile b/Makefile index a20fbafd62..f818eecaf3 100644 --- a/Makefile +++ b/Makefile @@ -334,6 +334,10 @@ all:: # Define DEFAULT_HELP_FORMAT to "man", "info" or "html" # (defaults to "man") if you want to have a different default when # "git help" is called without a parameter specifying the format. +# +# Define TEST_GIT_INDEX_VERSION to 2, 3 or 4 to run the test suite +# with a different indexfile format version. If it isn't set the index +# file format used is index-v[23]. GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -2212,6 +2216,9 @@ endif ifdef GIT_PERF_MAKE_OPTS @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@ endif +ifdef TEST_GIT_INDEX_VERSION + @echo TEST_GIT_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(TEST_GIT_INDEX_VERSION)))'\' >>$@ +endif ### Detect Python interpreter path changes ifndef NO_PYTHON diff --git a/read-cache.c b/read-cache.c index fb440b4d9d..f23c44a81a 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1220,6 +1220,42 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, #define INDEX_FORMAT_DEFAULT 3 +static int index_format_config(const char *var, const char *value, void *cb) +{ + unsigned int *version = cb; + if (!strcmp(var, "index.version")) { + *version = git_config_int(var, value); + return 0; + } + return 1; +} + +static unsigned int get_index_format_default(void) +{ + char *envversion = getenv("GIT_INDEX_VERSION"); + char *endp; + unsigned int version = INDEX_FORMAT_DEFAULT; + + if (!envversion) { + git_config(index_format_config, &version); + if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) { + warning(_("index.version set, but the value is invalid.\n" + "Using version %i"), INDEX_FORMAT_DEFAULT); + return INDEX_FORMAT_DEFAULT; + } + return version; + } + + version = strtoul(envversion, &endp, 10); + if (*endp || + version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) { + warning(_("GIT_INDEX_VERSION set, but the value is invalid.\n" + "Using version %i"), INDEX_FORMAT_DEFAULT); + version = INDEX_FORMAT_DEFAULT; + } + return version; +} + /* * dev/ino/uid/gid/size are also just tracked to the low 32 bits * Again - this is just a (very strong in practice) heuristic that @@ -1776,7 +1812,7 @@ int write_index(struct index_state *istate, int newfd) } if (!istate->version) - istate->version = INDEX_FORMAT_DEFAULT; + istate->version = get_index_format_default(); /* demote version 3 to version 2 when the latter suffices */ if (istate->version == 3 || istate->version == 2) diff --git a/t/t1600-index.sh b/t/t1600-index.sh new file mode 100755 index 0000000000..079d241145 --- /dev/null +++ b/t/t1600-index.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +test_description='index file specific tests' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo 1 >a +' + +test_expect_success 'bogus GIT_INDEX_VERSION issues warning' ' + ( + rm -f .git/index && + GIT_INDEX_VERSION=2bogus && + export GIT_INDEX_VERSION && + git add a 2>&1 | sed "s/[0-9]//" >actual.err && + sed -e "s/ Z$/ /" <<-\EOF >expect.err && + warning: GIT_INDEX_VERSION set, but the value is invalid. + Using version Z + EOF + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'out of bounds GIT_INDEX_VERSION issues warning' ' + ( + rm -f .git/index && + GIT_INDEX_VERSION=1 && + export GIT_INDEX_VERSION && + git add a 2>&1 | sed "s/[0-9]//" >actual.err && + sed -e "s/ Z$/ /" <<-\EOF >expect.err && + warning: GIT_INDEX_VERSION set, but the value is invalid. + Using version Z + EOF + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'no warning with bogus GIT_INDEX_VERSION and existing index' ' + ( + GIT_INDEX_VERSION=1 && + export GIT_INDEX_VERSION && + git add a 2>actual.err && + >expect.err && + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'out of bounds index.version issues warning' ' + ( + sane_unset GIT_INDEX_VERSION && + rm -f .git/index && + git config --add index.version 1 && + git add a 2>&1 | sed "s/[0-9]//" >actual.err && + sed -e "s/ Z$/ /" <<-\EOF >expect.err && + warning: index.version set, but the value is invalid. + Using version Z + EOF + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'GIT_INDEX_VERSION takes precedence over config' ' + ( + rm -f .git/index && + GIT_INDEX_VERSION=4 && + export GIT_INDEX_VERSION && + git config --add index.version 2 && + git add a 2>&1 && + echo 4 >expect && + test-index-version <.git/index >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh index 1d0879be06..29c1fb10ca 100755 --- a/t/t2104-update-index-skip-worktree.sh +++ b/t/t2104-update-index-skip-worktree.sh @@ -7,6 +7,8 @@ test_description='skip-worktree bit test' . ./test-lib.sh +test_set_index_version 3 + cat >expect.full </dev/null ||