]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/index-pack.c: write reverse indexes
authorTaylor Blau <me@ttaylorr.com>
Mon, 25 Jan 2021 23:37:26 +0000 (18:37 -0500)
committerJunio C Hamano <gitster@pobox.com>
Tue, 26 Jan 2021 02:32:43 +0000 (18:32 -0800)
Teach 'git index-pack' to optionally write and verify reverse index with
'--[no-]rev-index', as well as respecting the 'pack.writeReverseIndex'
configuration option.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-index-pack.txt
builtin/index-pack.c
t/t5325-reverse-index.sh [new file with mode: 0755]

index af0c26232c1e775cf5f4d56ee67c07b6a73a9104..69ba904d4491957dcf739097e739357aa5969891 100644 (file)
@@ -9,17 +9,18 @@ git-index-pack - Build pack index file for an existing packed archive
 SYNOPSIS
 --------
 [verse]
-'git index-pack' [-v] [-o <index-file>] <pack-file>
+'git index-pack' [-v] [-o <index-file>] [--[no-]rev-index] <pack-file>
 'git index-pack' --stdin [--fix-thin] [--keep] [-v] [-o <index-file>]
-                 [<pack-file>]
+                 [--[no-]rev-index] [<pack-file>]
 
 
 DESCRIPTION
 -----------
 Reads a packed archive (.pack) from the specified file, and
-builds a pack index file (.idx) for it.  The packed archive
-together with the pack index can then be placed in the
-objects/pack/ directory of a Git repository.
+builds a pack index file (.idx) for it. Optionally writes a
+reverse-index (.rev) for the specified pack. The packed
+archive together with the pack index can then be placed in
+the objects/pack/ directory of a Git repository.
 
 
 OPTIONS
@@ -35,6 +36,13 @@ OPTIONS
        fails if the name of packed archive does not end
        with .pack).
 
+--[no-]rev-index::
+       When this flag is provided, generate a reverse index
+       (a `.rev` file) corresponding to the given pack. If
+       `--verify` is given, ensure that the existing
+       reverse index is correct. Takes precedence over
+       `pack.writeReverseIndex`.
+
 --stdin::
        When this flag is provided, the pack is read from stdin
        instead and a copy is then written to <pack-file>. If
index c758f3b8e9640fa84b18df171c25bf3643cf5bbb..d5cd665b98bcbafe0c80cc2873e8885e739c7fbd 100644 (file)
@@ -17,7 +17,7 @@
 #include "promisor-remote.h"
 
 static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
+"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
 
 struct object_entry {
        struct pack_idx_entry idx;
@@ -1484,12 +1484,14 @@ static void write_special_file(const char *suffix, const char *msg,
 
 static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
+                 const char *final_rev_index_name, const char *curr_rev_index_name,
                  const char *keep_msg, const char *promisor_msg,
                  unsigned char *hash)
 {
        const char *report = "pack";
        struct strbuf pack_name = STRBUF_INIT;
        struct strbuf index_name = STRBUF_INIT;
+       struct strbuf rev_index_name = STRBUF_INIT;
        int err;
 
        if (!from_stdin) {
@@ -1524,6 +1526,16 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
        } else
                chmod(final_index_name, 0444);
 
+       if (curr_rev_index_name) {
+               if (final_rev_index_name != curr_rev_index_name) {
+                       if (!final_rev_index_name)
+                               final_rev_index_name = odb_pack_name(&rev_index_name, hash, "rev");
+                       if (finalize_object_file(curr_rev_index_name, final_rev_index_name))
+                               die(_("cannot store reverse index file"));
+               } else
+                       chmod(final_rev_index_name, 0444);
+       }
+
        if (do_fsck_object) {
                struct packed_git *p;
                p = add_packed_git(final_index_name, strlen(final_index_name), 0);
@@ -1553,6 +1565,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                }
        }
 
+       strbuf_release(&rev_index_name);
        strbuf_release(&index_name);
        strbuf_release(&pack_name);
 }
@@ -1578,6 +1591,12 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
                }
                return 0;
        }
+       if (!strcmp(k, "pack.writereverseindex")) {
+               if (git_config_bool(k, v))
+                       opts->flags |= WRITE_REV;
+               else
+                       opts->flags &= ~WRITE_REV;
+       }
        return git_default_config(k, v, cb);
 }
 
@@ -1695,12 +1714,14 @@ static void show_pack_info(int stat_only)
 
 int cmd_index_pack(int argc, const char **argv, const char *prefix)
 {
-       int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
+       int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
        const char *curr_index;
-       const char *index_name = NULL, *pack_name = NULL;
+       const char *curr_rev_index = NULL;
+       const char *index_name = NULL, *pack_name = NULL, *rev_index_name = NULL;
        const char *keep_msg = NULL;
        const char *promisor_msg = NULL;
        struct strbuf index_name_buf = STRBUF_INIT;
+       struct strbuf rev_index_name_buf = STRBUF_INIT;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
        unsigned char pack_hash[GIT_MAX_RAWSZ];
@@ -1727,6 +1748,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (prefix && chdir(prefix))
                die(_("Cannot come back to cwd"));
 
+       rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
+
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
@@ -1805,6 +1828,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                if (hash_algo == GIT_HASH_UNKNOWN)
                                        die(_("unknown hash algorithm '%s'"), arg);
                                repo_set_hash_algo(the_repository, hash_algo);
+                       } else if (!strcmp(arg, "--rev-index")) {
+                               rev_index = 1;
+                       } else if (!strcmp(arg, "--no-rev-index")) {
+                               rev_index = 0;
                        } else
                                usage(index_pack_usage);
                        continue;
@@ -1826,6 +1853,15 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (!index_name && pack_name)
                index_name = derive_filename(pack_name, "pack", "idx", &index_name_buf);
 
+       opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
+       if (rev_index) {
+               opts.flags |= verify ? WRITE_REV_VERIFY : WRITE_REV;
+               if (index_name)
+                       rev_index_name = derive_filename(index_name,
+                                                        "idx", "rev",
+                                                        &rev_index_name_buf);
+       }
+
        if (verify) {
                if (!index_name)
                        die(_("--verify with no packfile name given"));
@@ -1878,11 +1914,16 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;
        curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
+       if (rev_index)
+               curr_rev_index = write_rev_file(rev_index_name, idx_objects,
+                                               nr_objects, pack_hash,
+                                               opts.flags);
        free(idx_objects);
 
        if (!verify)
                final(pack_name, curr_pack,
                      index_name, curr_index,
+                     rev_index_name, curr_rev_index,
                      keep_msg, promisor_msg,
                      pack_hash);
        else
@@ -1893,10 +1934,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
 
        free(objects);
        strbuf_release(&index_name_buf);
+       strbuf_release(&rev_index_name_buf);
        if (pack_name == NULL)
                free((void *) curr_pack);
        if (index_name == NULL)
                free((void *) curr_index);
+       if (rev_index_name == NULL)
+               free((void *) curr_rev_index);
 
        /*
         * Let the caller know this pack is not self contained
diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh
new file mode 100755 (executable)
index 0000000..2dae213
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='on-disk reverse index'
+. ./test-lib.sh
+
+packdir=.git/objects/pack
+
+test_expect_success 'setup' '
+       test_commit base &&
+
+       pack=$(git pack-objects --all $packdir/pack) &&
+       rev=$packdir/pack-$pack.rev &&
+
+       test_path_is_missing $rev
+'
+
+test_index_pack () {
+       rm -f $rev &&
+       conf=$1 &&
+       shift &&
+       # remove the index since Windows won't overwrite an existing file
+       rm $packdir/pack-$pack.idx &&
+       git -c pack.writeReverseIndex=$conf index-pack "$@" \
+               $packdir/pack-$pack.pack
+}
+
+test_expect_success 'index-pack with pack.writeReverseIndex' '
+       test_index_pack "" &&
+       test_path_is_missing $rev &&
+
+       test_index_pack false &&
+       test_path_is_missing $rev &&
+
+       test_index_pack true &&
+       test_path_is_file $rev
+'
+
+test_expect_success 'index-pack with --[no-]rev-index' '
+       for conf in "" true false
+       do
+               test_index_pack "$conf" --rev-index &&
+               test_path_exists $rev &&
+
+               test_index_pack "$conf" --no-rev-index &&
+               test_path_is_missing $rev
+       done
+'
+
+test_expect_success 'index-pack can verify reverse indexes' '
+       test_when_finished "rm -f $rev" &&
+       test_index_pack true &&
+
+       test_path_is_file $rev &&
+       git index-pack --rev-index --verify $packdir/pack-$pack.pack &&
+
+       # Intentionally corrupt the reverse index.
+       chmod u+w $rev &&
+       printf "xxxx" | dd of=$rev bs=1 count=4 conv=notrunc &&
+
+       test_must_fail git index-pack --rev-index --verify \
+               $packdir/pack-$pack.pack 2>err &&
+       grep "validation error" err
+'
+
+test_expect_success 'index-pack infers reverse index name with -o' '
+       git index-pack --rev-index -o other.idx $packdir/pack-$pack.pack &&
+       test_path_is_file other.idx &&
+       test_path_is_file other.rev
+'
+
+test_done