Merge branch 'jk/repack-pack-writebitmaps-config'
authorJunio C Hamano <gitster@pobox.com>
Wed, 25 Jun 2014 19:23:19 +0000 (12:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 25 Jun 2014 19:23:19 +0000 (12:23 -0700)
* jk/repack-pack-writebitmaps-config:
t7700: drop explicit --no-pack-kept-objects from .keep test
repack: introduce repack.writeBitmaps config option
repack: simplify handling of --write-bitmap-index
pack-objects: stop respecting pack.writebitmaps

1  2 
Documentation/config.txt
builtin/pack-objects.c
builtin/repack.c
t/t5310-pack-bitmaps.sh
t/t7700-repack.sh
diff --combined Documentation/config.txt
index 9f467d3820a40d1281d29707e98fa16c2bbde63f,411bbe5a0dcc5ae2df84ba7df9f3e00752daffb4..1d718bdb9662735d9b446033607c5f2aa92f8a78
@@@ -78,8 -78,8 +78,8 @@@ be escaped: use `\"` for `"` and `\\` f
  
  The following escape sequences (beside `\"` and `\\`) are recognized:
  `\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
 -and `\b` for backspace (BS).  No other char escape sequence, nor octal
 -char sequences are valid.
 +and `\b` for backspace (BS).  Other char escape sequences (including octal
 +escape sequences) are invalid.
  
  Variable values ending in a `\` are continued on the next line in the
  customary UNIX fashion.
@@@ -131,13 -131,8 +131,13 @@@ Variable
  
  Note that this list is non-comprehensive and not necessarily complete.
  For command-specific variables, you will find a more detailed description
 -in the appropriate manual page. You will find a description of non-core
 -porcelain configuration variables in the respective porcelain documentation.
 +in the appropriate manual page.
 +
 +Other git-related tools may and do use their own variables.  When
 +inventing new variables for use in your own tool, make sure their
 +names do not conflict with those that are used by Git itself and
 +other popular tools, and describe them in your documentation.
 +
  
  advice.*::
        These variables control various optional help messages designed to
  --
        pushUpdateRejected::
                Set this variable to 'false' if you want to disable
 -              'pushNonFFCurrent', 'pushNonFFDefault',
 +              'pushNonFFCurrent',
                'pushNonFFMatching', 'pushAlreadyExists',
                'pushFetchFirst', and 'pushNeedsForce'
                simultaneously.
        pushNonFFCurrent::
                Advice shown when linkgit:git-push[1] fails due to a
                non-fast-forward update to the current branch.
 -      pushNonFFDefault::
 -              Advice to set 'push.default' to 'upstream' or 'current'
 -              when you ran linkgit:git-push[1] and pushed 'matching
 -              refs' by default (i.e. you did not provide an explicit
 -              refspec, and no 'push.default' configuration was set)
 -              and it resulted in a non-fast-forward error.
        pushNonFFMatching::
                Advice shown when you ran linkgit:git-push[1] and pushed
                'matching refs' explicitly (i.e. you used ':', or
@@@ -381,7 -382,7 +381,7 @@@ false), while all other repositories ar
  core.worktree::
        Set the path to the root of the working tree.
        This can be overridden by the GIT_WORK_TREE environment
 -      variable and the '--work-tree' command line option.
 +      variable and the '--work-tree' command-line option.
        The value can be an absolute path or relative to the path to
        the .git directory, which is either specified by --git-dir
        or GIT_DIR, or automatically discovered.
@@@ -489,7 -490,7 +489,7 @@@ core.deltaBaseCacheLimit:
        to avoid unpacking and decompressing frequently used base
        objects multiple times.
  +
 -Default is 16 MiB on all platforms.  This should be reasonable
 +Default is 96 MiB on all platforms.  This should be reasonable
  for all users/operating systems, except on the largest projects.
  You probably do not need to adjust this value.
  +
@@@ -523,7 -524,7 +523,7 @@@ core.askpass:
        environment variable. If not set, fall back to the value of the
        'SSH_ASKPASS' environment variable or, failing that, a simple password
        prompt. The external program shall be given a suitable prompt as
 -      command line argument and write the password on its STDOUT.
 +      command-line argument and write the password on its STDOUT.
  
  core.attributesfile::
        In addition to '.gitattributes' (per-directory) and
@@@ -544,9 -545,6 +544,9 @@@ core.commentchar:
        messages consider a line that begins with this character
        commented, and removes them after the editor returns
        (default '#').
 ++
 +If set to "auto", `git-commit` would select a character that is not
 +the beginning character of any line in existing commit messages.
  
  sequence.editor::
        Text editor used by `git rebase -i` for editing the rebase instruction file.
@@@ -561,23 -559,14 +561,23 @@@ core.pager:
        configuration, then `$PAGER`, and then the default chosen at
        compile time (usually 'less').
  +
 -When the `LESS` environment variable is unset, Git sets it to `FRSX`
 +When the `LESS` environment variable is unset, Git sets it to `FRX`
  (if `LESS` environment variable is set, Git does not change it at
  all).  If you want to selectively override Git's default setting
 -for `LESS`, you can set `core.pager` to e.g. `less -+S`.  This will
 +for `LESS`, you can set `core.pager` to e.g. `less -S`.  This will
  be passed to the shell by Git, which will translate the final
 -command to `LESS=FRSX less -+S`. The environment tells the command
 -to set the `S` option to chop long lines but the command line
 -resets it to the default to fold long lines.
 +command to `LESS=FRX less -S`. The environment does not set the
 +`S` option but the command line does, instructing less to truncate
 +long lines. Similarly, setting `core.pager` to `less -+F` will
 +deactivate the `F` option specified by the environment from the
 +command-line, deactivating the "quit if one screen" behavior of
 +`less`.  One can specifically activate some flags for particular
 +commands: for example, setting `pager.blame` to `less -S` enables
 +line truncation only for `git blame`.
 ++
 +Likewise, when the `LV` environment variable is unset, Git sets it
 +to `-c`.  You can override this setting by exporting `LV` with
 +another value or setting `core.pager` to `lv +c`.
  
  core.whitespace::
        A comma separated list of common whitespace problems to
@@@ -621,9 -610,9 +621,9 @@@ core.preloadindex:
  +
  This can speed up operations like 'git diff' and 'git status' especially
  on filesystems like NFS that have weak caching semantics and thus
 -relatively high IO latencies.  With this set to 'true', Git will do the
 +relatively high IO latencies.  When enabled, Git will do the
  index comparison to the filesystem data in parallel, allowing
 -overlapping IO's.
 +overlapping IO's.  Defaults to true.
  
  core.createObject::
        You can set this to 'link', in which case a hardlink followed by
@@@ -834,7 -823,7 +834,7 @@@ color.diff:
        commands will only use color when output is to the terminal.
        Defaults to false.
  +
 -This does not affect linkgit:git-format-patch[1] nor the
 +This does not affect linkgit:git-format-patch[1] or the
  'git-diff-{asterisk}' plumbing commands.  Can be overridden on the
  command line with the `--color[=<when>]` option.
  
@@@ -999,14 -988,6 +999,14 @@@ commit.cleanup:
        have to remove the help lines that begin with `#` in the commit log
        template yourself, if you do this).
  
 +commit.gpgsign::
 +
 +      A boolean to specify whether all commits should be GPG signed.
 +      Use of this option when doing operations such as rebase can
 +      result in a large number of commits being signed. It may be
 +      convenient to use an agent to avoid typing your GPG passphrase
 +      several times.
 +
  commit.status::
        A boolean to enable/disable inclusion of status information in the
        commit message template when using an editor to prepare the commit
@@@ -1122,10 -1103,6 +1122,10 @@@ format.signature:
        Set this variable to the empty string ("") to suppress
        signature generation.
  
 +format.signaturefile::
 +      Works just like format.signature except the contents of the
 +      file specified by this variable will be used as the signature.
 +
  format.suffix::
        The default for format-patch is to output files with the suffix
        `.patch`. Use this variable to change that suffix (make sure to
@@@ -1168,11 -1145,6 +1168,11 @@@ filter.<driver>.smudge:
        object to a worktree file upon checkout.  See
        linkgit:gitattributes[5] for details.
  
 +gc.aggressiveDepth::
 +      The depth parameter used in the delta compression
 +      algorithm used by 'git gc --aggressive'.  This defaults
 +      to 250.
 +
  gc.aggressiveWindow::
        The window size parameter used in the delta compression
        algorithm used by 'git gc --aggressive'.  This defaults
@@@ -1191,10 -1163,6 +1191,10 @@@ gc.autopacklimit:
        --auto` consolidates them into one larger pack.  The
        default value is 50.  Setting this to 0 disables it.
  
 +gc.autodetach::
 +      Make `git gc --auto` return immediately andrun in background
 +      if the system supports it. Default is true.
 +
  gc.packrefs::
        Running `git pack-refs` in a repository renders it
        unclonable by Git versions prior to 1.5.1.2 over dumb
@@@ -1336,7 -1304,7 +1336,7 @@@ grep.extendedRegexp:
  gpg.program::
        Use this custom program instead of "gpg" found on $PATH when
        making or verifying a PGP signature. The program must support the
 -      same command line interface as GPG, namely, to verify a detached
 +      same command-line interface as GPG, namely, to verify a detached
        signature, "gpg --verify $file - <$signature" is run, and the
        program is expected to signal a good signature by exiting with
        code 0, and to generate an ascii-armored detached signature, the
@@@ -1352,10 -1320,6 +1352,10 @@@ gui.diffcontext:
        Specifies how many context lines should be used in calls to diff
        made by the linkgit:git-gui[1]. The default is "5".
  
 +gui.displayuntracked::
 +      Determines if linkgit::git-gui[1] shows untracked files
 +      in the file list. The default is "true".
 +
  gui.encoding::
        Specifies the default encoding to use for displaying of
        file contents in linkgit:git-gui[1] and linkgit:gitk[1].
@@@ -1633,10 -1597,6 +1633,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].)
@@@ -1669,7 -1629,7 +1669,7 @@@ interactive.singlekey:
        linkgit:git-add[1], linkgit:git-checkout[1], linkgit:git-commit[1],
        linkgit:git-reset[1], and linkgit:git-stash[1]. Note that this
        setting is silently ignored if portable keystroke input
 -      is not available.
 +      is not available; requires the Perl module Term::ReadKey.
  
  log.abbrevCommit::
        If true, makes linkgit:git-log[1], linkgit:git-show[1], and
@@@ -1905,12 -1865,7 +1905,7 @@@ pack.useBitmaps:
        you are debugging pack bitmaps.
  
  pack.writebitmaps::
-       When true, git will write a bitmap index when packing all
-       objects to disk (e.g., when `git repack -a` is run).  This
-       index can speed up the "counting objects" phase of subsequent
-       packs created for clones and fetches, at the cost of some disk
-       space and extra time spent on the initial repack.  Defaults to
-       false.
+       This is a deprecated synonym for `repack.writeBitmaps`.
  
  pack.writeBitmapHashCache::
        When true, git will include a "hash cache" section in the bitmap
@@@ -1942,16 -1897,6 +1937,16 @@@ pretty.<name>:
        Note that an alias with the same name as a built-in format
        will be silently ignored.
  
 +pull.ff::
 +      By default, Git does not create an extra merge commit when merging
 +      a commit that is a descendant of the current commit. Instead, the
 +      tip of the current branch is fast-forwarded. When set to `false`,
 +      this variable tells Git to create an extra merge commit in such
 +      a case (equivalent to giving the `--no-ff` option from the command
 +      line). When set to `only`, only such fast-forward merges are
 +      allowed (equivalent to giving the `--ff-only` option from the
 +      command line).
 +
  pull.rebase::
        When true, rebase branches on top of the fetched branch, instead
        of merging the default branch from the default remote when "git
@@@ -2004,7 -1949,7 +1999,7 @@@ When pushing to a remote that is differ
  pull from, work as `current`.  This is the safest option and is suited
  for beginners.
  +
 -This mode will become the default in Git 2.0.
 +This mode has become the default in Git 2.0.
  
  * `matching` - push all branches having the same name on both ends.
    This makes the repository you are pushing to remember the set of
@@@ -2023,8 -1968,8 +2018,8 @@@ suitable for pushing into a shared cent
  people may add new branches there, or update the tip of existing
  branches outside your control.
  +
 -This is currently the default, but Git 2.0 will change the default
 -to `simple`.
 +This used to be the default, but not since Git 2.0 (`simple` is the
 +new default).
  
  --
  
@@@ -2101,10 -2046,6 +2096,10 @@@ receive.updateserverinfo:
        If set to true, git-receive-pack will run git-update-server-info
        after receiving data from git-push and updating refs.
  
 +receive.shallowupdate::
 +      If set to true, .git/shallow can be updated when new refs
 +      require new shallow roots. Otherwise those refs are rejected.
 +
  remote.pushdefault::
        The remote to push to by default.  Overrides
        `branch.<name>.remote` for all branches, and is overridden by
@@@ -2166,8 -2107,8 +2161,8 @@@ remote.<name>.vcs:
  
  remote.<name>.prune::
        When set to true, fetching from this remote by default will also
 -      remove any remote-tracking branches which no longer exist on the
 -      remote (as if the `--prune` option was give on the command line).
 +      remove any remote-tracking references that no longer exist on the
 +      remote (as if the `--prune` option was given on the command line).
        Overrides `fetch.prune` settings, if any.
  
  remotes.<group>::
@@@ -2187,7 -2128,15 +2182,15 @@@ repack.packKeptObjects:
        `--pack-kept-objects` was passed. See linkgit:git-repack[1] for
        details. Defaults to `false` normally, but `true` if a bitmap
        index is being written (either via `--write-bitmap-index` or
-       `pack.writeBitmaps`).
+       `repack.writeBitmaps`).
+ repack.writeBitmaps::
+       When true, git will write a bitmap index when packing all
+       objects to disk (e.g., when `git repack -a` is run).  This
+       index can speed up the "counting objects" phase of subsequent
+       packs created for clones and fetches, at the cost of some disk
+       space and extra time spent on the initial repack.  Defaults to
+       false.
  
  rerere.autoupdate::
        When set to true, `git-rerere` updates the index with the
@@@ -2305,11 -2254,9 +2308,11 @@@ status.submodulesummary:
        --summary-limit option of linkgit:git-submodule[1]). Please note
        that the summary output command will be suppressed for all
        submodules when `diff.ignoreSubmodules` is set to 'all' or only
 -      for those submodules where `submodule.<name>.ignore=all`. To
 +      for those submodules where `submodule.<name>.ignore=all`. The only
 +      exception to that rule is that status and commit will show staged
 +      submodule changes. To
        also view the summary for ignored submodules you can either use
 -      the --ignore-submodules=dirty command line option or the 'git
 +      the --ignore-submodules=dirty command-line option or the 'git
        submodule summary' command, which shows a similar output but does
        not honor these settings.
  
@@@ -2331,16 -2278,14 +2334,16 @@@ submodule.<name>.branch:
  submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
        submodule. It can be overridden by using the --[no-]recurse-submodules
 -      command line option to "git fetch" and "git pull".
 +      command-line option to "git fetch" and "git pull".
        This setting will override that from in the linkgit:gitmodules[5]
        file.
  
  submodule.<name>.ignore::
        Defines under what circumstances "git status" and the diff family show
        a submodule as modified. When set to "all", it will never be considered
 -      modified, "dirty" will ignore all changes to the submodules work tree and
 +      modified (but it will nonetheless show up in the output of status and
 +      commit when it has been staged), "dirty" will ignore all changes
 +      to the submodules work tree and
        takes only differences between the HEAD of the submodule and the commit
        recorded in the superproject into account. "untracked" will additionally
        let submodules with modified tracked files in their work tree show up.
@@@ -2373,13 -2318,6 +2376,13 @@@ transfer.unpackLimit:
        not set, the value of this variable is used instead.
        The default value is 100.
  
 +uploadarchive.allowUnreachable::
 +      If true, allow clients to use `git archive --remote` to request
 +      any tree, whether reachable from the ref tips or not. See the
 +      discussion in the `SECURITY` section of
 +      linkgit:git-upload-archive[1] for more details. Defaults to
 +      `false`.
 +
  uploadpack.hiderefs::
        String(s) `upload-pack` uses to decide which refs to omit
        from its initial advertisement.  Use more than one
diff --combined builtin/pack-objects.c
index de36c60ca11d248013c2de42d196f1aff8a2937b,217503169944eb90d6ef4dc1ab96c4674f14adf4..238b5021eb105007a42061d5f8febc455530da45
@@@ -708,7 -708,7 +708,7 @@@ static struct object_entry **compute_wr
  static off_t write_reused_pack(struct sha1file *f)
  {
        unsigned char buffer[8192];
 -      off_t to_write;
 +      off_t to_write, total;
        int fd;
  
        if (!is_pack_valid(reuse_packfile))
        if (reuse_packfile_offset < 0)
                reuse_packfile_offset = reuse_packfile->pack_size - 20;
  
 -      to_write = reuse_packfile_offset - sizeof(struct pack_header);
 +      total = to_write = reuse_packfile_offset - sizeof(struct pack_header);
  
        while (to_write) {
                int read_pack = xread(fd, buffer, sizeof(buffer));
  
                sha1write(f, buffer, read_pack);
                to_write -= read_pack;
 +
 +              /*
 +               * We don't know the actual number of objects written,
 +               * only how many bytes written, how many bytes total, and
 +               * how many objects total. So we can fake it by pretending all
 +               * objects we are writing are the same size. This gives us a
 +               * smooth progress meter, and at the end it matches the true
 +               * answer.
 +               */
 +              written = reuse_packfile_objects *
 +                              (((double)(total - to_write)) / total);
 +              display_progress(progress_state, written);
        }
  
        close(fd);
 -      written += reuse_packfile_objects;
 +      written = reuse_packfile_objects;
 +      display_progress(progress_state, written);
        return reuse_packfile_offset - sizeof(struct pack_header);
  }
  
@@@ -768,7 -755,7 +768,7 @@@ static void write_pack_file(void
        struct object_entry **write_order;
  
        if (progress > pack_to_stdout)
 -              progress_state = start_progress("Writing objects", nr_result);
 +              progress_state = start_progress(_("Writing objects"), nr_result);
        written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));
        write_order = compute_write_order();
  
                        f = create_tmp_packfile(&pack_tmp_name);
  
                offset = write_pack_header(f, nr_remaining);
 -              if (!offset)
 -                      die_errno("unable to write pack header");
  
                if (reuse_packfile) {
                        off_t packfile_size;
  
                if (!pack_to_stdout) {
                        struct stat st;
 -                      char tmpname[PATH_MAX];
 +                      struct strbuf tmpname = STRBUF_INIT;
  
                        /*
                         * Packs are runtime accessed in their mtime
                                utb.modtime = --last_mtime;
                                if (utime(pack_tmp_name, &utb) < 0)
                                        warning("failed utime() on %s: %s",
 -                                              tmpname, strerror(errno));
 +                                              pack_tmp_name, strerror(errno));
                        }
  
 -                      /* Enough space for "-<sha-1>.pack"? */
 -                      if (sizeof(tmpname) <= strlen(base_name) + 50)
 -                              die("pack base name '%s' too long", base_name);
 -                      snprintf(tmpname, sizeof(tmpname), "%s-", base_name);
 +                      strbuf_addf(&tmpname, "%s-", base_name);
  
                        if (write_bitmap_index) {
                                bitmap_writer_set_checksum(sha1);
                                bitmap_writer_build_type_index(written_list, nr_written);
                        }
  
 -                      finish_tmp_packfile(tmpname, pack_tmp_name,
 +                      finish_tmp_packfile(&tmpname, pack_tmp_name,
                                            written_list, nr_written,
                                            &pack_idx_opts, sha1);
  
                        if (write_bitmap_index) {
 -                              char *end_of_name_prefix = strrchr(tmpname, 0);
 -                              sprintf(end_of_name_prefix, "%s.bitmap", sha1_to_hex(sha1));
 +                              strbuf_addf(&tmpname, "%s.bitmap", sha1_to_hex(sha1));
  
                                stop_progress(&progress_state);
  
                                bitmap_writer_select_commits(indexed_commits, indexed_commits_nr, -1);
                                bitmap_writer_build(&to_pack);
                                bitmap_writer_finish(written_list, nr_written,
 -                                                   tmpname, write_bitmap_options);
 +                                                   tmpname.buf, write_bitmap_options);
                                write_bitmap_index = 0;
                        }
  
 +                      strbuf_release(&tmpname);
                        free(pack_tmp_name);
                        puts(sha1_to_hex(sha1));
                }
@@@ -1008,10 -1000,6 +1008,10 @@@ static void create_object_entry(const u
        entry->no_try_delta = no_try_delta;
  }
  
 +static const char no_closure_warning[] = N_(
 +"disabling bitmap writing, as some objects are not being packed"
 +);
 +
  static int add_object_entry(const unsigned char *sha1, enum object_type type,
                            const char *name, int exclude)
  {
        if (have_duplicate_entry(sha1, exclude, &index_pos))
                return 0;
  
 -      if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset))
 +      if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset)) {
 +              /* The pack is missing an object, so it will not have closure */
 +              if (write_bitmap_index) {
 +                      warning(_(no_closure_warning));
 +                      write_bitmap_index = 0;
 +              }
                return 0;
 +      }
  
        create_object_entry(sha1, type, pack_name_hash(name),
                            exclude, name && no_try_delta(name),
                            index_pos, found_pack, found_offset);
  
 -      display_progress(progress_state, to_pack.nr_objects);
 +      display_progress(progress_state, nr_result);
        return 1;
  }
  
@@@ -1051,7 -1033,7 +1051,7 @@@ static int add_object_entry_from_bitmap
  
        create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset);
  
 -      display_progress(progress_state, to_pack.nr_objects);
 +      display_progress(progress_state, nr_result);
        return 1;
  }
  
@@@ -1076,7 -1058,7 +1076,7 @@@ static int pbase_tree_cache_ix_incr(in
  static struct pbase_tree {
        struct pbase_tree *next;
        /* This is a phony "cache" entry; we are not
 -       * going to evict it nor find it through _get()
 +       * going to evict it or find it through _get()
         * mechanism -- this is for the toplevel node that
         * would almost always change with any commit.
         */
@@@ -1233,9 -1215,12 +1233,9 @@@ static int check_pbase_path(unsigned ha
        if (0 <= pos)
                return 1;
        pos = -pos - 1;
 -      if (done_pbase_paths_alloc <= done_pbase_paths_num) {
 -              done_pbase_paths_alloc = alloc_nr(done_pbase_paths_alloc);
 -              done_pbase_paths = xrealloc(done_pbase_paths,
 -                                          done_pbase_paths_alloc *
 -                                          sizeof(unsigned));
 -      }
 +      ALLOC_GROW(done_pbase_paths,
 +                 done_pbase_paths_num + 1,
 +                 done_pbase_paths_alloc);
        done_pbase_paths_num++;
        if (pos < done_pbase_paths_num)
                memmove(done_pbase_paths + pos + 1,
@@@ -2104,7 -2089,7 +2104,7 @@@ static int add_ref_tag(const char *path
  {
        unsigned char peeled[20];
  
 -      if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
 +      if (starts_with(path, "refs/tags/") && /* is a tag? */
            !peel_ref(path, peeled)        && /* peelable? */
            packlist_find(&to_pack, peeled, NULL))      /* object packed? */
                add_object_entry(sha1, OBJ_TAG, NULL, 0);
@@@ -2171,7 -2156,7 +2171,7 @@@ static void prepare_pack(int window, in
        if (nr_deltas && n > 1) {
                unsigned nr_done = 0;
                if (progress)
 -                      progress_state = start_progress("Compressing objects",
 +                      progress_state = start_progress(_("Compressing objects"),
                                                        nr_deltas);
                qsort(delta_list, n, sizeof(*delta_list), type_size_sort);
                ll_find_deltas(delta_list, n, window+1, depth, &nr_done);
@@@ -2214,10 -2199,6 +2214,6 @@@ static int git_pack_config(const char *
                cache_max_small_delta_size = git_config_int(k, v);
                return 0;
        }
-       if (!strcmp(k, "pack.writebitmaps")) {
-               write_bitmap_index = git_config_bool(k, v);
-               return 0;
-       }
        if (!strcmp(k, "pack.writebitmaphashcache")) {
                if (git_config_bool(k, v))
                        write_bitmap_options |= BITMAP_OPT_HASH_CACHE;
@@@ -2439,29 -2420,23 +2435,29 @@@ static void loosen_unused_packed_object
        }
  }
  
 +/*
 + * This tracks any options which a reader of the pack might
 + * not understand, and which would therefore prevent blind reuse
 + * of what we have on disk.
 + */
 +static int pack_options_allow_reuse(void)
 +{
 +      return allow_ofs_delta;
 +}
 +
  static int get_object_list_from_bitmap(struct rev_info *revs)
  {
        if (prepare_bitmap_walk(revs) < 0)
                return -1;
  
 -      if (!reuse_partial_packfile_from_bitmap(
 +      if (pack_options_allow_reuse() &&
 +          !reuse_partial_packfile_from_bitmap(
                        &reuse_packfile,
                        &reuse_packfile_objects,
                        &reuse_packfile_offset)) {
                assert(reuse_packfile_objects);
                nr_result += reuse_packfile_objects;
 -
 -              if (progress) {
 -                      fprintf(stderr, "Reusing existing pack: %d, done.\n",
 -                              reuse_packfile_objects);
 -                      fflush(stderr);
 -              }
 +              display_progress(progress_state, nr_result);
        }
  
        traverse_bitmap_commit_list(&add_object_entry_from_bitmap);
@@@ -2478,9 -2453,6 +2474,9 @@@ static void get_object_list(int ac, con
        save_commit_buffer = 0;
        setup_revisions(ac, av, &revs, NULL);
  
 +      /* make sure shallows are read */
 +      is_repository_shallow();
 +
        while (fgets(line, sizeof(line), stdin) != NULL) {
                int len = strlen(line);
                if (len && line[len - 1] == '\n')
                                write_bitmap_index = 0;
                                continue;
                        }
 +                      if (starts_with(line, "--shallow ")) {
 +                              unsigned char sha1[20];
 +                              if (get_sha1_hex(line + 10, sha1))
 +                                      die("not an SHA-1 '%s'", line + 10);
 +                              register_shallow(sha1);
 +                              continue;
 +                      }
                        die("not a rev '%s'", line);
                }
                if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
@@@ -2645,7 -2610,7 +2641,7 @@@ int cmd_pack_objects(int argc, const ch
                OPT_END(),
        };
  
 -      read_replace_refs = 0;
 +      check_replace_refs = 0;
  
        reset_pack_idx_option(&pack_idx_opts);
        git_config(git_pack_config, NULL);
        prepare_packed_git();
  
        if (progress)
 -              progress_state = start_progress("Counting objects", 0);
 +              progress_state = start_progress(_("Counting objects"), 0);
        if (!use_internal_rev_list)
                read_object_list_from_stdin();
        else {
diff --combined builtin/repack.c
index 36c1cf9c2544d579e2b12116e731c0f6cb7dfb71,cd4d4d4273665880fff66029df6419b7493d4e2c..ff2216a7aaefa3b38385301e4e0d8bb8b94e4ea0
@@@ -10,7 -10,7 +10,7 @@@
  
  static int delta_base_offset = 1;
  static int pack_kept_objects = -1;
- static int write_bitmaps = -1;
+ static int write_bitmaps;
  static char *packdir, *packtmp;
  
  static const char *const git_repack_usage[] = {
@@@ -28,7 -28,8 +28,8 @@@ static int repack_config(const char *va
                pack_kept_objects = git_config_bool(var, value);
                return 0;
        }
-       if (!strcmp(var, "pack.writebitmaps")) {
+       if (!strcmp(var, "repack.writebitmaps") ||
+           !strcmp(var, "pack.writebitmaps")) {
                write_bitmaps = git_config_bool(var, value);
                return 0;
        }
@@@ -88,7 -89,7 +89,7 @@@ static void get_non_kept_pack_filenames
                return;
  
        while ((e = readdir(dir)) != NULL) {
 -              if (suffixcmp(e->d_name, ".pack"))
 +              if (!ends_with(e->d_name, ".pack"))
                        continue;
  
                len = strlen(e->d_name) - strlen(".pack");
@@@ -140,16 -141,16 +141,16 @@@ int cmd_repack(int argc, const char **a
        struct string_list rollback = STRING_LIST_INIT_NODUP;
        struct string_list existing_packs = STRING_LIST_INIT_DUP;
        struct strbuf line = STRBUF_INIT;
 -      int nr_packs, ext, ret, failed;
 +      int ext, ret, failed;
        FILE *out;
  
        /* variables to be filled by option parsing */
        int pack_everything = 0;
        int delete_redundant = 0;
 -      char *unpack_unreachable = NULL;
 -      int window = 0, window_memory = 0;
 -      int depth = 0;
 -      int max_pack_size = 0;
 +      const char *unpack_unreachable = NULL;
 +      const char *window = NULL, *window_memory = NULL;
 +      const char *depth = NULL;
 +      const char *max_pack_size = NULL;
        int no_reuse_delta = 0, no_reuse_object = 0;
        int no_update_server_info = 0;
        int quiet = 0;
                                N_("write bitmap index")),
                OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
                                N_("with -A, do not loosen objects older than this")),
 -              OPT_INTEGER(0, "window", &window,
 +              OPT_STRING(0, "window", &window, N_("n"),
                                N_("size of the window used for delta compression")),
 -              OPT_INTEGER(0, "window-memory", &window_memory,
 +              OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
                                N_("same as the above, but limit memory size instead of entries count")),
 -              OPT_INTEGER(0, "depth", &depth,
 +              OPT_STRING(0, "depth", &depth, N_("n"),
                                N_("limits the maximum delta depth")),
 -              OPT_INTEGER(0, "max-pack-size", &max_pack_size,
 +              OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"),
                                N_("maximum size of each packfile")),
                OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
                                N_("repack objects in packs marked with .keep")),
                                git_repack_usage, 0);
  
        if (pack_kept_objects < 0)
-               pack_kept_objects = write_bitmaps > 0;
+               pack_kept_objects = write_bitmaps;
  
        packdir = mkpathdup("%s/pack", get_object_directory());
        packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid());
        argv_array_push(&cmd_args, "--all");
        argv_array_push(&cmd_args, "--reflog");
        if (window)
 -              argv_array_pushf(&cmd_args, "--window=%u", window);
 +              argv_array_pushf(&cmd_args, "--window=%s", window);
        if (window_memory)
 -              argv_array_pushf(&cmd_args, "--window-memory=%u", window_memory);
 +              argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory);
        if (depth)
 -              argv_array_pushf(&cmd_args, "--depth=%u", depth);
 +              argv_array_pushf(&cmd_args, "--depth=%s", depth);
        if (max_pack_size)
 -              argv_array_pushf(&cmd_args, "--max_pack_size=%u", max_pack_size);
 +              argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size);
        if (no_reuse_delta)
                argv_array_pushf(&cmd_args, "--no-reuse-delta");
        if (no_reuse_object)
                argv_array_pushf(&cmd_args, "--no-reuse-object");
-       if (write_bitmaps >= 0)
-               argv_array_pushf(&cmd_args, "--%swrite-bitmap-index",
-                                write_bitmaps ? "" : "no-");
+       if (write_bitmaps)
+               argv_array_push(&cmd_args, "--write-bitmap-index");
  
        if (pack_everything & ALL_INTO_ONE) {
                get_non_kept_pack_filenames(&existing_packs);
        if (ret)
                return ret;
  
 -      nr_packs = 0;
        out = xfdopen(cmd.out, "r");
        while (strbuf_getline(&line, out, '\n') != EOF) {
                if (line.len != 40)
                        die("repack: Expecting 40 character sha1 lines only from pack-objects.");
                string_list_append(&names, line.buf);
 -              nr_packs++;
        }
        fclose(out);
        ret = finish_command(&cmd);
                return ret;
        argv_array_clear(&cmd_args);
  
 -      if (!nr_packs && !quiet)
 +      if (!names.nr && !quiet)
                printf("Nothing new to pack.\n");
  
        /*
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
                        char *fname, *fname_old;
 -                      fname = mkpathdup("%s/%s%s", packdir,
 +                      fname = mkpathdup("%s/pack-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (!file_exists(fname)) {
                                free(fname);
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
                        char *fname;
 -                      fname = mkpath("%s/old-pack-%s%s",
 +                      fname = mkpath("%s/old-%s%s",
                                        packdir,
                                        item->string,
                                        exts[ext].name);
diff --combined t/t5310-pack-bitmaps.sh
index f4f02ba918535d5c40a30585a54469bc12ab96d3,d81f2c7c725da551ce9897481a800965fca6ce9d..0580258c91a07aabe2773cce04df47d3c183b425
@@@ -3,10 -3,6 +3,10 @@@
  test_description='exercise basic bitmap functionality'
  . ./test-lib.sh
  
 +objpath () {
 +      echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')"
 +}
 +
  test_expect_success 'setup repo with moderate-sized history' '
        for i in $(test_seq 1 10); do
                test_commit $i
@@@ -18,7 -14,7 +18,7 @@@
        git checkout master &&
        blob=$(echo tagged-blob | git hash-object -w --stdin) &&
        git tag tagged-blob $blob &&
-       git config pack.writebitmaps true &&
+       git config repack.writebitmaps true &&
        git config pack.writebitmaphashcache true
  '
  
@@@ -95,10 -91,7 +95,10 @@@ test_expect_success 'fetch (partial bit
  
  test_expect_success 'incremental repack cannot create bitmaps' '
        test_commit more-1 &&
 -      test_must_fail git repack -d
 +      find .git/objects/pack -name "*.bitmap" >expect &&
 +      git repack -d &&
 +      find .git/objects/pack -name "*.bitmap" >actual &&
 +      test_cmp expect actual
  '
  
  test_expect_success 'incremental repack can disable bitmaps' '
@@@ -119,33 -112,6 +119,33 @@@ test_expect_success 'fetch (full bitmap
        test_cmp expect actual
  '
  
 +test_expect_success 'create objects for missing-HAVE tests' '
 +      blob=$(echo "missing have" | git hash-object -w --stdin) &&
 +      tree=$(printf "100644 blob $blob\tfile\n" | git mktree) &&
 +      parent=$(echo parent | git commit-tree $tree) &&
 +      commit=$(echo commit | git commit-tree $tree -p $parent) &&
 +      cat >revs <<-EOF
 +      HEAD
 +      ^HEAD^
 +      ^$commit
 +      EOF
 +'
 +
 +test_expect_success 'pack with missing blob' '
 +      rm $(objpath $blob) &&
 +      git pack-objects --stdout --revs <revs >/dev/null
 +'
 +
 +test_expect_success 'pack with missing tree' '
 +      rm $(objpath $tree) &&
 +      git pack-objects --stdout --revs <revs >/dev/null
 +'
 +
 +test_expect_success 'pack with missing parent' '
 +      rm $(objpath $parent) &&
 +      git pack-objects --stdout --revs <revs >/dev/null
 +'
 +
  test_lazy_prereq JGIT '
        type jgit
  '
diff --combined t/t7700-repack.sh
index 61e6ed37aa6fd6bff8bfe4d5c267c0ed3cad3db4,44407ae7c94d4c22c13f078d26a84221ff6a14a1..021c5479bdf4665e815590dc05a0831e7d92c53c
@@@ -17,11 -17,11 +17,11 @@@ test_expect_success 'objects in packs m
        # The second pack will contain the excluded object
        packsha1=$(git rev-list --objects --all | grep file2 |
                git pack-objects pack) &&
 -      touch -r pack-$packsha1.pack pack-$packsha1.keep &&
 +      >pack-$packsha1.keep &&
        objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 |
                sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") &&
        mv pack-* .git/objects/pack/ &&
-       git repack --no-pack-kept-objects -A -d -l &&
+       git repack -A -d -l &&
        git prune-packed &&
        for p in .git/objects/pack/*.idx; do
                idx=$(basename $p)
@@@ -53,7 -53,7 +53,7 @@@ test_expect_success 'writing bitmaps vi
  
  test_expect_success 'writing bitmaps via config can duplicate .keep objects' '
        # build on $objsha1, $packsha1, and .keep state from previous
-       git -c pack.writebitmaps=true repack -Adl &&
+       git -c repack.writebitmaps=true repack -Adl &&
        test_when_finished "found_duplicate_object=" &&
        for p in .git/objects/pack/*.idx; do
                idx=$(basename $p)