Merge branch 'jk/pack-bitmap'
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Feb 2014 22:01:48 +0000 (14:01 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Feb 2014 22:01:48 +0000 (14:01 -0800)
Borrow the bitmap index into packfiles from JGit to speed up
enumeration of objects involved in a commit range without having to
fully traverse the history.

* jk/pack-bitmap: (26 commits)
ewah: unconditionally ntohll ewah data
ewah: support platforms that require aligned reads
read-cache: use get_be32 instead of hand-rolled ntoh_l
block-sha1: factor out get_be and put_be wrappers
do not discard revindex when re-preparing packfiles
pack-bitmap: implement optional name_hash cache
t/perf: add tests for pack bitmaps
t: add basic bitmap functionality tests
count-objects: recognize .bitmap in garbage-checking
repack: consider bitmaps when performing repacks
repack: handle optional files created by pack-objects
repack: turn exts array into array-of-struct
repack: stop using magic number for ARRAY_SIZE(exts)
pack-objects: implement bitmap writing
rev-list: add bitmap mode to speed up object lists
pack-objects: use bitmaps when packing objects
pack-objects: split add_object_entry
pack-bitmap: add support for bitmap indexes
documentation: add documentation for the bitmap format
ewah: compressed bitmap implementation
...

14 files changed:
1  2 
Documentation/config.txt
Documentation/git-repack.txt
Documentation/rev-list-options.txt
Makefile
block-sha1/sha1.c
builtin/pack-objects.c
builtin/repack.c
builtin/rev-list.c
cache.h
pack-write.c
read-cache.c
revision.c
revision.h
sha1_file.c
diff --combined Documentation/config.txt
index 7eec746950232b2bf20b30097ecab4f4a1508373,499a3c43608ecca1525756df78c31df1a1519a23..040197b10ea5a46e6ba643b28de17d2100cb129b
@@@ -567,10 -567,6 +567,10 @@@ be passed to the shell by Git, which wi
  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.
 ++
 +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
@@@ -992,14 -988,6 +992,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
@@@ -1870,6 -1858,31 +1870,31 @@@ pack.packSizeLimit:
        Common unit suffixes of 'k', 'm', or 'g' are
        supported.
  
+ pack.useBitmaps::
+       When true, git will use pack bitmaps (if available) when packing
+       to stdout (e.g., during the server side of a fetch). Defaults to
+       true. You should not generally need to turn this off unless
+       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.
+ pack.writeBitmapHashCache::
+       When true, git will include a "hash cache" section in the bitmap
+       index (if one is written). This cache can be used to feed git's
+       delta heuristics, potentially leading to better deltas between
+       bitmapped and non-bitmapped objects (e.g., when serving a fetch
+       between an older, bitmapped pack and objects that have been
+       pushed since the last gc). The downside is that it consumes 4
+       bytes per object of disk space, and that JGit's bitmap
+       implementation does not understand it, causing it to complain if
+       Git and JGit are used on the same repository. Defaults to false.
  pager.<cmd>::
        If the value is boolean, turns on or off pagination of the
        output of a particular Git subcommand when writing to a tty.
@@@ -1889,16 -1902,6 +1914,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
@@@ -2048,10 -2051,6 +2073,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
@@@ -2113,8 -2112,8 +2138,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>::
index 509cf73e50542758d0ef3930f56fdb5dd0183aac,dad186c694cb6b03ec64f3767abc84f83cacc350..002cfd5eb959ce7c8afea32388477f3a1062c485
@@@ -9,12 -9,12 +9,12 @@@ git-repack - Pack unpacked objects in 
  SYNOPSIS
  --------
  [verse]
- 'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [--window=<n>] [--depth=<n>]
+ 'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [--window=<n>] [--depth=<n>]
  
  DESCRIPTION
  -----------
  
 -This script is used to combine all objects that do not currently
 +This command is used to combine all objects that do not currently
  reside in a "pack", into a pack.  It can also be used to re-organize
  existing packs into a single, more efficient pack.
  
@@@ -110,6 -110,13 +110,13 @@@ other objects in that pack they alread
        The default is unlimited, unless the config variable
        `pack.packSizeLimit` is set.
  
+ -b::
+ --write-bitmap-index::
+       Write a reachability bitmap index as part of the repack. This
+       only makes sense when used with `-a` or `-A`, as the bitmaps
+       must be able to refer to all reachable objects. This option
+       overrides the setting of `pack.writebitmaps`.
  
  Configuration
  -------------
index 03533af7152e8b137cd3d885de3ec273b91d4791,c236b857b0f1ae10eb2993b1703f7c9f4faa2152..9a3da3646e58f6155a6ff3397eddfd239703447a
@@@ -18,27 -18,33 +18,27 @@@ ordering and formatting options, such a
  -<number>::
  -n <number>::
  --max-count=<number>::
 -
        Limit the number of commits to output.
  
  --skip=<number>::
 -
        Skip 'number' commits before starting to show the commit output.
  
  --since=<date>::
  --after=<date>::
 -
        Show commits more recent than a specific date.
  
  --until=<date>::
  --before=<date>::
 -
        Show commits older than a specific date.
  
  ifdef::git-rev-list[]
  --max-age=<timestamp>::
  --min-age=<timestamp>::
 -
        Limit the commits output to specified time range.
  endif::git-rev-list[]
  
  --author=<pattern>::
  --committer=<pattern>::
 -
        Limit the commits output to ones with author/committer
        header lines that match the specified pattern (regular
        expression).  With more than one `--author=<pattern>`,
@@@ -46,6 -52,7 +46,6 @@@
        chosen (similarly for multiple `--committer=<pattern>`).
  
  --grep-reflog=<pattern>::
 -
        Limit the commits output to ones with reflog entries that
        match the specified pattern (regular expression). With
        more than one `--grep-reflog`, commits whose reflog message
@@@ -53,6 -60,7 +53,6 @@@
        error to use this option unless `--walk-reflogs` is in use.
  
  --grep=<pattern>::
 -
        Limit the commits output to ones with log message that
        matches the specified pattern (regular expression).  With
        more than one `--grep=<pattern>`, commits whose message
@@@ -63,39 -71,46 +63,39 @@@ When `--show-notes` is in effect, the m
  if it is part of the log message.
  
  --all-match::
 -      Limit the commits output to ones that match all given --grep,
 +      Limit the commits output to ones that match all given `--grep`,
        instead of ones that match at least one.
  
  -i::
  --regexp-ignore-case::
 -
 -      Match the regexp limiting patterns without regard to letters case.
 +      Match the regular expression limiting patterns without regard to letter
 +      case.
  
  --basic-regexp::
 -
        Consider the limiting patterns to be basic regular expressions;
        this is the default.
  
  -E::
  --extended-regexp::
 -
        Consider the limiting patterns to be extended regular expressions
        instead of the default basic regular expressions.
  
  -F::
  --fixed-strings::
 -
        Consider the limiting patterns to be fixed strings (don't interpret
        pattern as a regular expression).
  
  --perl-regexp::
 -
 -      Consider the limiting patterns to be Perl-compatible regexp.
 +      Consider the limiting patterns to be Perl-compatible regular expressions.
        Requires libpcre to be compiled in.
  
  --remove-empty::
 -
        Stop when a given path disappears from the tree.
  
  --merges::
 -
        Print only merge commits. This is exactly the same as `--min-parents=2`.
  
  --no-merges::
 -
        Do not print commits with more than one parent. This is
        exactly the same as `--max-parents=1`.
  
  --max-parents=<number>::
  --no-min-parents::
  --no-max-parents::
 -
        Show only commits which have at least (or at most) that many parent
        commits. In particular, `--max-parents=1` is the same as `--no-merges`,
        `--min-parents=2` is the same as `--merges`.  `--max-parents=0`
@@@ -122,26 -138,31 +122,26 @@@ parents) and `--max-parents=-1` (negati
        brought in to your history by such a merge.
  
  --not::
 -
        Reverses the meaning of the '{caret}' prefix (or lack thereof)
 -      for all following revision specifiers, up to the next '--not'.
 +      for all following revision specifiers, up to the next `--not`.
  
  --all::
 -
        Pretend as if all the refs in `refs/` are listed on the
        command line as '<commit>'.
  
  --branches[=<pattern>]::
 -
        Pretend as if all the refs in `refs/heads` are listed
        on the command line as '<commit>'. If '<pattern>' is given, limit
        branches to ones matching given shell glob. If pattern lacks '?',
        '{asterisk}', or '[', '/{asterisk}' at the end is implied.
  
  --tags[=<pattern>]::
 -
        Pretend as if all the refs in `refs/tags` are listed
        on the command line as '<commit>'. If '<pattern>' is given, limit
        tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}',
        or '[', '/{asterisk}' at the end is implied.
  
  --remotes[=<pattern>]::
 -
        Pretend as if all the refs in `refs/remotes` are listed
        on the command line as '<commit>'. If '<pattern>' is given, limit
        remote-tracking branches to ones matching given shell glob.
        is automatically prepended if missing. If pattern lacks '?', '{asterisk}',
        or '[', '/{asterisk}' at the end is implied.
  
 ---ignore-missing::
 +--exclude=<glob-pattern>::
  
 +      Do not include refs matching '<glob-pattern>' that the next `--all`,
 +      `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
 +      consider. Repetitions of this option accumulate exclusion patterns
 +      up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
 +      `--glob` option (other options or arguments do not clear
 +      accumlated patterns).
 ++
 +The patterns given should not begin with `refs/heads`, `refs/tags`, or
 +`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
 +respectively, and they must begin with `refs/` when applied to `--glob`
 +or `--all`. If a trailing '/{asterisk}' is intended, it must be given
 +explicitly.
 +
 +--ignore-missing::
        Upon seeing an invalid object name in the input, pretend as if
        the bad input was not given.
  
  ifndef::git-rev-list[]
  --bisect::
 -
        Pretend as if the bad bisection ref `refs/bisect/bad`
        was listed and as if it was followed by `--not` and the good
        bisection refs `refs/bisect/good-*` on the command
  endif::git-rev-list[]
  
  --stdin::
 -
        In addition to the '<commit>' listed on the command
        line, read them from the standard input. If a '--' separator is
        seen, stop reading commits and start reading paths to limit the
  
  ifdef::git-rev-list[]
  --quiet::
 -
        Don't print anything to standard output.  This form
        is primarily meant to allow the caller to
        test the exit status to see if a range of objects is fully
        connected (or not).  It is faster than redirecting stdout
 -      to /dev/null as the output does not have to be formatted.
 +      to `/dev/null` as the output does not have to be formatted.
  endif::git-rev-list[]
  
  --cherry-mark::
 -
        Like `--cherry-pick` (see below) but mark equivalent commits
        with `=` rather than omitting them, and inequivalent ones with `+`.
  
  --cherry-pick::
 -
        Omit any commit that introduces the same change as
 -      another commit on the "other side" when the set of
 +      another commit on the ``other side'' when the set of
        commits are limited with symmetric difference.
  +
  For example, if you have two branches, `A` and `B`, a usual way
  to list all commits on only one side of them is with
  `--left-right` (see the example below in the description of
 -the `--left-right` option).  It however shows the commits that were cherry-picked
 -from the other branch (for example, "3rd on b" may be cherry-picked
 -from branch A).  With this option, such pairs of commits are
 +the `--left-right` option). However, it shows the commits that were
 +cherry-picked from the other branch (for example, ``3rd on b'' may be
 +cherry-picked from branch A). With this option, such pairs of commits are
  excluded from the output.
  
  --left-only::
  --right-only::
 -
        List only commits on the respective side of a symmetric range,
        i.e. only those which would be marked `<` resp. `>` by
        `--left-right`.
@@@ -225,6 -238,7 +225,6 @@@ More precisely, `--cherry-pick --right-
  list.
  
  --cherry::
 -
        A synonym for `--right-only --cherry-mark --no-merges`; useful to
        limit the output to the commits on our side and mark those that
        have been applied to the other side of a forked history with
  
  -g::
  --walk-reflogs::
 -
        Instead of walking the commit ancestry chain, walk
        reflog entries from the most recent one to older ones.
        When this option is used you cannot specify commits to
        exclude (that is, '{caret}commit', 'commit1..commit2',
        nor 'commit1\...commit2' notations cannot be used).
  +
 -With '\--pretty' format other than oneline (for obvious reasons),
 +With `--pretty` format other than `oneline` (for obvious reasons),
  this causes the output to have two extra lines of information
  taken from the reflog.  By default, 'commit@\{Nth}' notation is
  used in the output.  When the starting commit is specified as
  'commit@\{now}', output also uses 'commit@\{timestamp}' notation
 -instead.  Under '\--pretty=oneline', the commit message is
 +instead.  Under `--pretty=oneline`, the commit message is
  prefixed with this information on the same line.
 -This option cannot be combined with '\--reverse'.
 +This option cannot be combined with `--reverse`.
  See also linkgit:git-reflog[1].
  
  --merge::
 -
        After a failed merge, show refs that touch files having a
        conflict and don't exist on all heads to merge.
  
  --boundary::
 -
        Output excluded boundary commits. Boundary commits are
        prefixed with `-`.
  
+ ifdef::git-rev-list[]
+ --use-bitmap-index::
+       Try to speed up the traversal using the pack bitmap index (if
+       one is available). Note that when traversing with `--objects`,
+       trees and blobs will not have their associated path printed.
+ endif::git-rev-list[]
  --
  
  History Simplification
@@@ -270,9 -295,11 +278,9 @@@ is how to do it, as there are various s
  The following options select the commits to be shown:
  
  <paths>::
 -
        Commits modifying the given <paths> are selected.
  
  --simplify-by-decoration::
 -
        Commits that are referred by some branch or tag are selected.
  
  Note that extra commits can be shown to give a meaningful history.
  The following options affect the way the simplification is performed:
  
  Default mode::
 -
        Simplifies the history to the simplest history explaining the
        final state of the tree. Simplest because it prunes some side
        branches if the end result is the same (i.e. merging branches
        with the same content)
  
  --full-history::
 -
        Same as the default mode, but does not prune some history.
  
  --dense::
 -
        Only the selected commits are shown, plus some to have a
        meaningful history.
  
  --sparse::
 -
        All commits in the simplified history are shown.
  
  --simplify-merges::
 -
 -      Additional option to '--full-history' to remove some needless
 +      Additional option to `--full-history` to remove some needless
        merges from the resulting history, as there are no selected
        commits contributing to this merge.
  
  --ancestry-path::
 -
        When given a range of commits to display (e.g. 'commit1..commit2'
        or 'commit2 {caret}commit1'), only display commits that exist
        directly on the ancestry chain between the 'commit1' and
@@@ -327,35 -360,36 +335,35 @@@ The horizontal line of history A---Q i
  each merge.  The commits are:
  
  * `I` is the initial commit, in which `foo` exists with contents
 -  "asdf", and a file `quux` exists with contents "quux".  Initial
 +  ``asdf'', and a file `quux` exists with contents ``quux''. Initial
    commits are compared to an empty tree, so `I` is !TREESAME.
  
 -* In `A`, `foo` contains just "foo".
 +* In `A`, `foo` contains just ``foo''.
  
  * `B` contains the same change as `A`.  Its merge `M` is trivial and
    hence TREESAME to all parents.
  
 -* `C` does not change `foo`, but its merge `N` changes it to "foobar",
 +* `C` does not change `foo`, but its merge `N` changes it to ``foobar'',
    so it is not TREESAME to any parent.
  
 -* `D` sets `foo` to "baz".  Its merge `O` combines the strings from
 -  `N` and `D` to "foobarbaz"; i.e., it is not TREESAME to any parent.
 +* `D` sets `foo` to ``baz''. Its merge `O` combines the strings from
 +  `N` and `D` to ``foobarbaz''; i.e., it is not TREESAME to any parent.
  
 -* `E` changes `quux` to "xyzzy", and its merge `P` combines the
 -  strings to "quux xyzzy".  `P` is TREESAME to `O`, but not to `E`.
 +* `E` changes `quux` to ``xyzzy'', and its merge `P` combines the
 +  strings to ``quux xyzzy''. `P` is TREESAME to `O`, but not to `E`.
  
  * `X` is an independent root commit that added a new file `side`, and `Y`
    modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and
    `Q` is TREESAME to `P`, but not to `Y`.
  
 -'rev-list' walks backwards through history, including or excluding
 -commits based on whether '\--full-history' and/or parent rewriting
 -(via '\--parents' or '\--children') are used.  The following settings
 +`rev-list` walks backwards through history, including or excluding
 +commits based on whether `--full-history` and/or parent rewriting
 +(via `--parents` or `--children`) are used. The following settings
  are available.
  
  Default mode::
 -
        Commits are included if they are not TREESAME to any parent
 -      (though this can be changed, see '\--sparse' below).  If the
 +      (though this can be changed, see `--sparse` below).  If the
        commit was a merge, and it was TREESAME to one parent, follow
        only that parent.  (Even if there are several TREESAME
        parents, follow only one of them.)  Otherwise, follow all
@@@ -374,11 -408,12 +382,11 @@@ available, removed `B` from considerati
  considered via `N`, but is TREESAME.  Root commits are compared to an
  empty tree, so `I` is !TREESAME.
  +
 -Parent/child relations are only visible with --parents, but that does
 +Parent/child relations are only visible with `--parents`, but that does
  not affect the commits selected in default mode, so we have shown the
  parent lines.
  
  --full-history without parent rewriting::
 -
        This mode differs from the default in one point: always follow
        all parents of a merge, even if it is TREESAME to one of them.
        Even if more than one side of the merge has commits that are
@@@ -398,8 -433,9 +406,8 @@@ about the parent/child relationships be
  them disconnected.
  
  --full-history with parent rewriting::
 -
        Ordinary commits are only included if they are !TREESAME
 -      (though this can be changed, see '\--sparse' below).
 +      (though this can be changed, see `--sparse` below).
  +
  Merges are always included.  However, their parent list is rewritten:
  Along each parent, prune away commits that are not included
@@@ -413,7 -449,7 +421,7 @@@ themselves.  This results i
          `-------------'
  -----------------------------------------------------------------------
  +
 -Compare to '\--full-history' without rewriting above.  Note that `E`
 +Compare to `--full-history` without rewriting above.  Note that `E`
  was pruned away because it is TREESAME, but the parent list of P was
  rewritten to contain `E`'s parent `I`.  The same happened for `C` and
  `N`, and `X`, `Y` and `Q`.
@@@ -422,19 -458,22 +430,19 @@@ In addition to the above settings, you 
  affects inclusion:
  
  --dense::
 -
        Commits that are walked are included if they are not TREESAME
        to any parent.
  
  --sparse::
 -
        All commits that are walked are included.
  +
 -Note that without '\--full-history', this still simplifies merges: if
 +Note that without `--full-history`, this still simplifies merges: if
  one of the parents is TREESAME, we follow only that one, so the other
  sides of the merge are never walked.
  
  --simplify-merges::
 -
        First, build a history graph in the same way that
 -      '\--full-history' with parent rewriting does (see above).
 +      `--full-history` with parent rewriting does (see above).
  +
  Then simplify each commit `C` to its replacement `C'` in the final
  history according to the following rules:
  --
  +
  The effect of this is best shown by way of comparing to
 -'\--full-history' with parent rewriting.  The example turns into:
 +`--full-history` with parent rewriting.  The example turns into:
  +
  -----------------------------------------------------------------------
          .-A---M---N---O
          `---------'
  -----------------------------------------------------------------------
  +
 -Note the major differences in `N`, `P` and `Q` over '--full-history':
 +Note the major differences in `N`, `P`, and `Q` over `--full-history`:
  +
  --
  * `N`'s parent list had `I` removed, because it is an ancestor of the
  Finally, there is a fifth simplification mode available:
  
  --ancestry-path::
 -
        Limit the displayed commits to those directly on the ancestry
 -      chain between the "from" and "to" commits in the given commit
 -      range. I.e. only display commits that are ancestor of the "to"
 -      commit, and descendants of the "from" commit.
 +      chain between the ``from'' and ``to'' commits in the given commit
 +      range. I.e. only display commits that are ancestor of the ``to''
 +      commit and descendants of the ``from'' commit.
  +
  As an example use case, consider the following commit history:
  +
  A regular 'D..M' computes the set of commits that are ancestors of `M`,
  but excludes the ones that are ancestors of `D`. This is useful to see
  what happened to the history leading to `M` since `D`, in the sense
 -that "what does `M` have that did not exist in `D`". The result in this
 +that ``what does `M` have that did not exist in `D`''. The result in this
  example would be all the commits, except `A` and `B` (and `D` itself,
  of course).
  +
  When we want to find out what commits in `M` are contaminated with the
  bug introduced by `D` and need fixing, however, we might want to view
  only the subset of 'D..M' that are actually descendants of `D`, i.e.
 -excluding `C` and `K`. This is exactly what the '--ancestry-path'
 +excluding `C` and `K`. This is exactly what the `--ancestry-path`
  option does. Applied to the 'D..M' range, it results in:
  +
  -----------------------------------------------------------------------
                                L--M
  -----------------------------------------------------------------------
  
 -The '\--simplify-by-decoration' option allows you to view only the
 +The `--simplify-by-decoration` option allows you to view only the
  big picture of the topology of the history, by omitting commits
  that are not referenced by tags.  Commits are marked as !TREESAME
  (in other words, kept after history simplification rules described
@@@ -529,47 -569,50 +537,47 @@@ Bisection Helper
  ~~~~~~~~~~~~~~~~~
  
  --bisect::
 -
 -Limit output to the one commit object which is roughly halfway between
 -included and excluded commits. Note that the bad bisection ref
 -`refs/bisect/bad` is added to the included commits (if it
 -exists) and the good bisection refs `refs/bisect/good-*` are
 -added to the excluded commits (if they exist). Thus, supposing there
 -are no refs in `refs/bisect/`, if
 -
 +      Limit output to the one commit object which is roughly halfway between
 +      included and excluded commits. Note that the bad bisection ref
 +      `refs/bisect/bad` is added to the included commits (if it
 +      exists) and the good bisection refs `refs/bisect/good-*` are
 +      added to the excluded commits (if they exist). Thus, supposing there
 +      are no refs in `refs/bisect/`, if
 ++
  -----------------------------------------------------------------------
        $ git rev-list --bisect foo ^bar ^baz
  -----------------------------------------------------------------------
 -
 ++
  outputs 'midpoint', the output of the two commands
 -
 ++
  -----------------------------------------------------------------------
        $ git rev-list foo ^midpoint
        $ git rev-list midpoint ^bar ^baz
  -----------------------------------------------------------------------
 -
 ++
  would be of roughly the same length.  Finding the change which
  introduces a regression is thus reduced to a binary search: repeatedly
  generate and test new 'midpoint's until the commit chain is of length
  one.
  
  --bisect-vars::
 -
 -This calculates the same as `--bisect`, except that refs in
 -`refs/bisect/` are not used, and except that this outputs
 -text ready to be eval'ed by the shell. These lines will assign the
 -name of the midpoint revision to the variable `bisect_rev`, and the
 -expected number of commits to be tested after `bisect_rev` is tested
 -to `bisect_nr`, the expected number of commits to be tested if
 -`bisect_rev` turns out to be good to `bisect_good`, the expected
 -number of commits to be tested if `bisect_rev` turns out to be bad to
 -`bisect_bad`, and the number of commits we are bisecting right now to
 -`bisect_all`.
 +      This calculates the same as `--bisect`, except that refs in
 +      `refs/bisect/` are not used, and except that this outputs
 +      text ready to be eval'ed by the shell. These lines will assign the
 +      name of the midpoint revision to the variable `bisect_rev`, and the
 +      expected number of commits to be tested after `bisect_rev` is tested
 +      to `bisect_nr`, the expected number of commits to be tested if
 +      `bisect_rev` turns out to be good to `bisect_good`, the expected
 +      number of commits to be tested if `bisect_rev` turns out to be bad to
 +      `bisect_bad`, and the number of commits we are bisecting right now to
 +      `bisect_all`.
  
  --bisect-all::
 -
 -This outputs all the commit objects between the included and excluded
 -commits, ordered by their distance to the included and excluded
 -commits. Refs in `refs/bisect/` are not used. The farthest
 -from them is displayed first. (This is the only one displayed by
 -`--bisect`.)
 +      This outputs all the commit objects between the included and excluded
 +      commits, ordered by their distance to the included and excluded
 +      commits. Refs in `refs/bisect/` are not used. The farthest
 +      from them is displayed first. (This is the only one displayed by
 +      `--bisect`.)
  +
  This is useful because it makes it easy to choose a good commit to
  test when you want to avoid to test some of them for some reason (they
@@@ -619,8 -662,9 +627,8 @@@ avoid showing the commits from two para
  together.
  
  --reverse::
 -
        Output the commits in reverse order.
 -      Cannot be combined with '\--walk-reflogs'.
 +      Cannot be combined with `--walk-reflogs`.
  
  Object Traversal
  ~~~~~~~~~~~~~~~~
  These options are mostly targeted for packing of Git repositories.
  
  --objects::
 -
        Print the object IDs of any object referenced by the listed
 -      commits.  '--objects foo ^bar' thus means "send me
 +      commits.  `--objects foo ^bar` thus means ``send me
        all object IDs which I need to download if I have the commit
 -      object 'bar', but not 'foo'".
 +      object _bar_ but not _foo_''.
  
  --objects-edge::
 -
 -      Similar to '--objects', but also print the IDs of excluded
 -      commits prefixed with a "-" character.  This is used by
 -      linkgit:git-pack-objects[1] to build "thin" pack, which records
 +      Similar to `--objects`, but also print the IDs of excluded
 +      commits prefixed with a ``-'' character.  This is used by
 +      linkgit:git-pack-objects[1] to build ``thin'' pack, which records
        objects in deltified form based on objects contained in these
        excluded commits to reduce network traffic.
  
  --unpacked::
 -
 -      Only useful with '--objects'; print the object IDs that are not
 +      Only useful with `--objects`; print the object IDs that are not
        in packs.
  
  --no-walk[=(sorted|unsorted)]::
 -
        Only show the given commits, but do not traverse their ancestors.
        This has no effect if a range is specified. If the argument
 -      "unsorted" is given, the commits are show in the order they were
 -      given on the command line. Otherwise (if "sorted" or no argument
 -      was given), the commits are show in reverse chronological order
 +      `unsorted` is given, the commits are shown in the order they were
 +      given on the command line. Otherwise (if `sorted` or no argument
 +      was given), the commits are shown in reverse chronological order
        by commit time.
  
  --do-walk::
 -
 -      Overrides a previous --no-walk.
 +      Overrides a previous `--no-walk`.
  
  Commit Formatting
  ~~~~~~~~~~~~~~~~~
@@@ -667,41 -716,46 +675,41 @@@ endif::git-rev-list[
  include::pretty-options.txt[]
  
  --relative-date::
 -
        Synonym for `--date=relative`.
  
  --date=(relative|local|default|iso|rfc|short|raw)::
 -
        Only takes effect for dates shown in human-readable format, such
 -      as when using "--pretty". `log.date` config variable sets a default
 -      value for log command's --date option.
 +      as when using `--pretty`. `log.date` config variable sets a default
 +      value for the log command's `--date` option.
  +
  `--date=relative` shows dates relative to the current time,
 -e.g. "2 hours ago".
 +e.g. ``2 hours ago''.
  +
 -`--date=local` shows timestamps in user's local timezone.
 +`--date=local` shows timestamps in user's local time zone.
  +
  `--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
  +
  `--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
 -format, often found in E-mail messages.
 +format, often found in email messages.
  +
 -`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
 +`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format.
  +
  `--date=raw` shows the date in the internal raw Git format `%s %z` format.
  +
 -`--date=default` shows timestamps in the original timezone
 +`--date=default` shows timestamps in the original time zone
  (either committer's or author's).
  
  ifdef::git-rev-list[]
  --header::
 -
        Print the contents of the commit in raw-format; each record is
        separated with a NUL character.
  endif::git-rev-list[]
  
  --parents::
 -
        Print also the parents of the commit (in the form "commit parent...").
        Also enables parent rewriting, see 'History Simplification' below.
  
  --children::
 -
        Print also the children of the commit (in the form "commit child...").
        Also enables parent rewriting, see 'History Simplification' below.
  
@@@ -711,6 -765,7 +719,6 @@@ ifdef::git-rev-list[
  endif::git-rev-list[]
  
  --left-right::
 -
        Mark which side of a symmetric diff a commit is reachable from.
        Commits from the left side are prefixed with `<` and those from
        the right with `>`.  If combined with `--boundary`, those
@@@ -740,6 -795,7 +748,6 @@@ you would get an output like this
  -----------------------------------------------------------------------
  
  --graph::
 -
        Draw a text-based graphical representation of the commit history
        on the left hand side of the output.  This may cause extra lines
        to be printed in between commits, in order for the graph history
  +
  This enables parent rewriting, see 'History Simplification' below.
  +
 -This implies the '--topo-order' option by default, but the
 -'--date-order' option may also be specified.
 +This implies the `--topo-order` option by default, but the
 +`--date-order` option may also be specified.
  
  ifdef::git-rev-list[]
  --count::
        Print a number stating how many commits would have been
        listed, and suppress all other output.  When used together
 -      with '--left-right', instead print the counts for left and
 +      with `--left-right`, instead print the counts for left and
        right commits, separated by a tab. When used together with
 -      '--cherry-mark', omit patch equivalent commits from these
 +      `--cherry-mark`, omit patch equivalent commits from these
        counts and print the count for equivalent commits separated
        by a tab.
  endif::git-rev-list[]
  
 -
  ifndef::git-rev-list[]
  Diff Formatting
  ~~~~~~~~~~~~~~~
  
 -Below are listed options that control the formatting of diff output.
 +Listed below are options that control the formatting of diff output.
  Some of them are specific to linkgit:git-rev-list[1], however other diff
  options may be given. See linkgit:git-diff-files[1] for more options.
  
  -c::
 -
        With this option, diff output for a merge commit
        shows the differences from each of the parents to the merge result
        simultaneously instead of showing pairwise diff between a parent
        which were modified from all parents.
  
  --cc::
 -
 -      This flag implies the '-c' option and further compresses the
 +      This flag implies the `-c` option and further compresses the
        patch output by omitting uninteresting hunks whose contents in
        the parents have only two variants and the merge result picks
        one of them without modification.
  
  -m::
 -
        This flag makes the merge commits show the full diff like
        regular commits; for each merge parent, a separate log entry
        and diff is generated. An exception is that only diff against
 -      the first parent is shown when '--first-parent' option is given;
 +      the first parent is shown when `--first-parent` option is given;
        in that case, the output represents the changes the merge
        brought _into_ the then-current branch.
  
  -r::
 -
        Show recursive diffs.
  
  -t::
 -
 -      Show the tree objects in the diff output. This implies '-r'.
 +      Show the tree objects in the diff output. This implies `-r`.
  endif::git-rev-list[]
diff --combined Makefile
index c3213bd54b453ff5b96bc4bec184e4d878312185,555d44c17bde8245f693c433841454a8f696128d..d4ce53a71b3ffd3b2a9d115279880d3e1aeb03a6
+++ b/Makefile
@@@ -452,6 -452,7 +452,6 @@@ SCRIPT_SH += git-am.s
  SCRIPT_SH += git-bisect.sh
  SCRIPT_SH += git-difftool--helper.sh
  SCRIPT_SH += git-filter-branch.sh
 -SCRIPT_SH += git-lost-found.sh
  SCRIPT_SH += git-merge-octopus.sh
  SCRIPT_SH += git-merge-one-file.sh
  SCRIPT_SH += git-merge-resolve.sh
@@@ -555,7 -556,6 +555,7 @@@ TEST_PROGRAMS_NEED_X += test-dat
  TEST_PROGRAMS_NEED_X += test-delta
  TEST_PROGRAMS_NEED_X += test-dump-cache-tree
  TEST_PROGRAMS_NEED_X += test-genrandom
 +TEST_PROGRAMS_NEED_X += test-hashmap
  TEST_PROGRAMS_NEED_X += test-index-version
  TEST_PROGRAMS_NEED_X += test-line-buffer
  TEST_PROGRAMS_NEED_X += test-match-trees
@@@ -587,8 -587,11 +587,8 @@@ BUILT_INS += git-cherry$
  BUILT_INS += git-cherry-pick$X
  BUILT_INS += git-format-patch$X
  BUILT_INS += git-fsck-objects$X
 -BUILT_INS += git-get-tar-commit-id$X
  BUILT_INS += git-init$X
  BUILT_INS += git-merge-subtree$X
 -BUILT_INS += git-peek-remote$X
 -BUILT_INS += git-repo-config$X
  BUILT_INS += git-show$X
  BUILT_INS += git-stage$X
  BUILT_INS += git-status$X
@@@ -664,6 -667,8 +664,8 @@@ LIB_H += diff.
  LIB_H += diffcore.h
  LIB_H += dir.h
  LIB_H += exec_cmd.h
+ LIB_H += ewah/ewok.h
+ LIB_H += ewah/ewok_rlw.h
  LIB_H += fetch-pack.h
  LIB_H += fmt-merge-msg.h
  LIB_H += fsck.h
@@@ -672,7 -677,7 +674,7 @@@ LIB_H += git-compat-util.
  LIB_H += gpg-interface.h
  LIB_H += graph.h
  LIB_H += grep.h
 -LIB_H += hash.h
 +LIB_H += hashmap.h
  LIB_H += help.h
  LIB_H += http.h
  LIB_H += kwset.h
@@@ -691,8 -696,10 +693,10 @@@ LIB_H += notes-merge.
  LIB_H += notes-utils.h
  LIB_H += notes.h
  LIB_H += object.h
+ LIB_H += pack-objects.h
  LIB_H += pack-revindex.h
  LIB_H += pack.h
+ LIB_H += pack-bitmap.h
  LIB_H += parse-options.h
  LIB_H += patch-ids.h
  LIB_H += pathspec.h
@@@ -796,6 -803,10 +800,10 @@@ LIB_OBJS += dir.
  LIB_OBJS += editor.o
  LIB_OBJS += entry.o
  LIB_OBJS += environment.o
+ LIB_OBJS += ewah/bitmap.o
+ LIB_OBJS += ewah/ewah_bitmap.o
+ LIB_OBJS += ewah/ewah_io.o
+ LIB_OBJS += ewah/ewah_rlw.o
  LIB_OBJS += exec_cmd.o
  LIB_OBJS += fetch-pack.o
  LIB_OBJS += fsck.o
@@@ -803,7 -814,7 +811,7 @@@ LIB_OBJS += gettext.
  LIB_OBJS += gpg-interface.o
  LIB_OBJS += graph.o
  LIB_OBJS += grep.o
 -LIB_OBJS += hash.o
 +LIB_OBJS += hashmap.o
  LIB_OBJS += help.o
  LIB_OBJS += hex.o
  LIB_OBJS += ident.o
@@@ -827,7 -838,10 +835,10 @@@ LIB_OBJS += notes-cache.
  LIB_OBJS += notes-merge.o
  LIB_OBJS += notes-utils.o
  LIB_OBJS += object.o
+ LIB_OBJS += pack-bitmap.o
+ LIB_OBJS += pack-bitmap-write.o
  LIB_OBJS += pack-check.o
+ LIB_OBJS += pack-objects.o
  LIB_OBJS += pack-revindex.o
  LIB_OBJS += pack-write.o
  LIB_OBJS += pager.o
@@@ -929,7 -943,6 +940,7 @@@ BUILTIN_OBJS += builtin/fmt-merge-msg.
  BUILTIN_OBJS += builtin/for-each-ref.o
  BUILTIN_OBJS += builtin/fsck.o
  BUILTIN_OBJS += builtin/gc.o
 +BUILTIN_OBJS += builtin/get-tar-commit-id.o
  BUILTIN_OBJS += builtin/grep.o
  BUILTIN_OBJS += builtin/hash-object.o
  BUILTIN_OBJS += builtin/help.o
@@@ -981,6 -994,7 +992,6 @@@ BUILTIN_OBJS += builtin/show-ref.
  BUILTIN_OBJS += builtin/stripspace.o
  BUILTIN_OBJS += builtin/symbolic-ref.o
  BUILTIN_OBJS += builtin/tag.o
 -BUILTIN_OBJS += builtin/tar-tree.o
  BUILTIN_OBJS += builtin/unpack-file.o
  BUILTIN_OBJS += builtin/unpack-objects.o
  BUILTIN_OBJS += builtin/update-index.o
@@@ -1585,7 -1599,6 +1596,7 @@@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PA
  PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
  TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
  DIFF_SQ = $(subst ','\'',$(DIFF))
 +PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
  
  LIBS = $(GITLIBS) $(EXTLIBS)
  
@@@ -1774,7 -1787,7 +1785,7 @@@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEF
  
  git.res: git.rc GIT-VERSION-FILE
        $(QUIET_RC)$(RC) \
 -        $(join -DMAJOR= -DMINOR= -DPATCH=, $(wordlist 1,3,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
 +        $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
          -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" $< -o $@
  
  ifndef NO_PERL
@@@ -1790,12 -1803,9 +1801,12 @@@ perl/PM.stamp: FORC
  perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
  
 -$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
 +PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ)
 +$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
 +      INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
 +      INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
        sed -e '1{' \
            -e '        s|#!.*perl|#!$(PERL_PATH_SQ)|' \
            -e '        h' \
        chmod +x $@+ && \
        mv $@+ $@
  
 +GIT-PERL-DEFINES: FORCE
 +      @FLAGS='$(PERL_DEFINES)'; \
 +          if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
 +              echo >&2 "    * new perl-specific parameters"; \
 +              echo "$$FLAGS" >$@; \
 +          fi
 +
  
  .PHONY: gitweb
  gitweb:
@@@ -2051,10 -2054,10 +2062,10 @@@ git-imap-send$X: imap-send.o GIT-LDFLAG
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
  
 -git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
 +git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL)
 -git-http-push$X: revision.o http.o http-push.o GIT-LDFLAGS $(GITLIBS)
 +git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
@@@ -2480,8 -2483,9 +2491,9 @@@ profile-clean
        $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
  
  clean: profile-clean coverage-clean
-       $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
-               builtin/*.o $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
+       $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o
+       $(RM) xdiff/*.o vcs-svn/*.o ewah/*.o builtin/*.o
+       $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
        $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
        $(RM) -r bin-wrappers $(dep_dirs)
@@@ -2502,8 -2506,7 +2514,8 @@@ ifndef NO_TCLT
        $(MAKE) -C git-gui clean
  endif
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
 -      $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS
 +      $(RM) GIT-USER-AGENT GIT-PREFIX
 +      $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PYTHON-VARS
  
  .PHONY: all install profile-clean clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --combined block-sha1/sha1.c
index e1a1eb609754a745da956a6994d23aec3c4c9c05,6d637bd81e8f9b34bbbf71f5172cbb3537c7f435..22b125cf8c122e3a1716f34778fa5595454fe76a
    #define setW(x, val) (W(x) = (val))
  #endif
  
- /*
-  * Performance might be improved if the CPU architecture is OK with
-  * unaligned 32-bit loads and a fast ntohl() is available.
-  * Otherwise fall back to byte loads and shifts which is portable,
-  * and is faster on architectures with memory alignment issues.
-  */
- #if defined(__i386__) || defined(__x86_64__) || \
-     defined(_M_IX86) || defined(_M_X64) || \
-     defined(__ppc__) || defined(__ppc64__) || \
-     defined(__powerpc__) || defined(__powerpc64__) || \
-     defined(__s390__) || defined(__s390x__)
- #define get_be32(p)   ntohl(*(unsigned int *)(p))
- #define put_be32(p, v)        do { *(unsigned int *)(p) = htonl(v); } while (0)
- #else
- #define get_be32(p)   ( \
-       (*((unsigned char *)(p) + 0) << 24) | \
-       (*((unsigned char *)(p) + 1) << 16) | \
-       (*((unsigned char *)(p) + 2) <<  8) | \
-       (*((unsigned char *)(p) + 3) <<  0) )
- #define put_be32(p, v)        do { \
-       unsigned int __v = (v); \
-       *((unsigned char *)(p) + 0) = __v >> 24; \
-       *((unsigned char *)(p) + 1) = __v >> 16; \
-       *((unsigned char *)(p) + 2) = __v >>  8; \
-       *((unsigned char *)(p) + 3) = __v >>  0; } while (0)
- #endif
  /* This "rolls" over the 512-bit array */
  #define W(x) (array[(x)&15])
  
@@@ -274,10 -242,10 +242,10 @@@ void blk_SHA1_Final(unsigned char hasho
        padlen[1] = htonl((uint32_t)(ctx->size << 3));
  
        i = ctx->size & 63;
 -      blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i)));
 +      blk_SHA1_Update(ctx, pad, 1 + (63 & (55 - i)));
        blk_SHA1_Update(ctx, padlen, 8);
  
        /* Output hash */
        for (i = 0; i < 5; i++)
 -              put_be32(hashout + i*4, ctx->H[i]);
 +              put_be32(hashout + i * 4, ctx->H[i]);
  }
diff --combined builtin/pack-objects.c
index 541667f1026d7ba62be8e029c31138d5661f65c7,fd741970e61c674c628f2e9c8ae48e08d4996961..c73337931b0c2d456801de75a4a17e83b2091753
  #include "diff.h"
  #include "revision.h"
  #include "list-objects.h"
+ #include "pack-objects.h"
  #include "progress.h"
  #include "refs.h"
  #include "streaming.h"
  #include "thread-utils.h"
+ #include "pack-bitmap.h"
  
  static const char *pack_usage[] = {
        N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
        NULL
  };
  
- struct object_entry {
-       struct pack_idx_entry idx;
-       unsigned long size;     /* uncompressed size */
-       struct packed_git *in_pack;     /* already in pack */
-       off_t in_pack_offset;
-       struct object_entry *delta;     /* delta base object */
-       struct object_entry *delta_child; /* deltified objects who bases me */
-       struct object_entry *delta_sibling; /* other deltified objects who
-                                            * uses the same base as me
-                                            */
-       void *delta_data;       /* cached delta (uncompressed) */
-       unsigned long delta_size;       /* delta data size (uncompressed) */
-       unsigned long z_delta_size;     /* delta data size (compressed) */
-       enum object_type type;
-       enum object_type in_pack_type;  /* could be delta */
-       uint32_t hash;                  /* name hint hash */
-       unsigned char in_pack_header_size;
-       unsigned preferred_base:1; /*
-                                   * we do not pack this, but is available
-                                   * to be used as the base object to delta
-                                   * objects against.
-                                   */
-       unsigned no_try_delta:1;
-       unsigned tagged:1; /* near the very tip of refs */
-       unsigned filled:1; /* assigned write-order */
- };
  /*
-  * Objects we are going to pack are collected in objects array (dynamically
-  * expanded).  nr_objects & nr_alloc controls this array.  They are stored
-  * in the order we see -- typically rev-list --objects order that gives us
-  * nice "minimum seek" order.
+  * Objects we are going to pack are collected in the `to_pack` structure.
+  * It contains an array (dynamically expanded) of the object data, and a map
+  * that can resolve SHA1s to their position in the array.
   */
- static struct object_entry *objects;
+ static struct packing_data to_pack;
  static struct pack_idx_entry **written_list;
- static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
+ static uint32_t nr_result, nr_written;
  
  static int non_empty;
  static int reuse_delta = 1, reuse_object = 1;
@@@ -83,27 -58,43 +58,43 @@@ static struct progress *progress_state
  static int pack_compression_level = Z_DEFAULT_COMPRESSION;
  static int pack_compression_seen;
  
+ static struct packed_git *reuse_packfile;
+ static uint32_t reuse_packfile_objects;
+ static off_t reuse_packfile_offset;
+ static int use_bitmap_index = 1;
+ static int write_bitmap_index;
+ static uint16_t write_bitmap_options;
  static unsigned long delta_cache_size = 0;
  static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
  static unsigned long cache_max_small_delta_size = 1000;
  
  static unsigned long window_memory_limit = 0;
  
- /*
-  * The object names in objects array are hashed with this hashtable,
-  * to help looking up the entry by object name.
-  * This hashtable is built after all the objects are seen.
-  */
- static int *object_ix;
- static int object_ix_hashsz;
- static struct object_entry *locate_object_entry(const unsigned char *sha1);
  /*
   * stats
   */
  static uint32_t written, written_delta;
  static uint32_t reused, reused_delta;
  
+ /*
+  * Indexed commits
+  */
+ static struct commit **indexed_commits;
+ static unsigned int indexed_commits_nr;
+ static unsigned int indexed_commits_alloc;
+ static void index_commit_for_bitmap(struct commit *commit)
+ {
+       if (indexed_commits_nr >= indexed_commits_alloc) {
+               indexed_commits_alloc = (indexed_commits_alloc + 32) * 2;
+               indexed_commits = xrealloc(indexed_commits,
+                       indexed_commits_alloc * sizeof(struct commit *));
+       }
+       indexed_commits[indexed_commits_nr++] = commit;
+ }
  
  static void *get_delta(struct object_entry *entry)
  {
@@@ -553,12 -544,12 +544,12 @@@ static int mark_tagged(const char *path
                       void *cb_data)
  {
        unsigned char peeled[20];
-       struct object_entry *entry = locate_object_entry(sha1);
+       struct object_entry *entry = packlist_find(&to_pack, sha1, NULL);
  
        if (entry)
                entry->tagged = 1;
        if (!peel_ref(path, peeled)) {
-               entry = locate_object_entry(peeled);
+               entry = packlist_find(&to_pack, peeled, NULL);
                if (entry)
                        entry->tagged = 1;
        }
@@@ -633,9 -624,10 +624,10 @@@ static struct object_entry **compute_wr
  {
        unsigned int i, wo_end, last_untagged;
  
-       struct object_entry **wo = xmalloc(nr_objects * sizeof(*wo));
+       struct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));
+       struct object_entry *objects = to_pack.objects;
  
-       for (i = 0; i < nr_objects; i++) {
+       for (i = 0; i < to_pack.nr_objects; i++) {
                objects[i].tagged = 0;
                objects[i].filled = 0;
                objects[i].delta_child = NULL;
         * Make sure delta_sibling is sorted in the original
         * recency order.
         */
-       for (i = nr_objects; i > 0;) {
+       for (i = to_pack.nr_objects; i > 0;) {
                struct object_entry *e = &objects[--i];
                if (!e->delta)
                        continue;
         * Give the objects in the original recency order until
         * we see a tagged tip.
         */
-       for (i = wo_end = 0; i < nr_objects; i++) {
+       for (i = wo_end = 0; i < to_pack.nr_objects; i++) {
                if (objects[i].tagged)
                        break;
                add_to_write_order(wo, &wo_end, &objects[i]);
        /*
         * Then fill all the tagged tips.
         */
-       for (; i < nr_objects; i++) {
+       for (; i < to_pack.nr_objects; i++) {
                if (objects[i].tagged)
                        add_to_write_order(wo, &wo_end, &objects[i]);
        }
        /*
         * And then all remaining commits and tags.
         */
-       for (i = last_untagged; i < nr_objects; i++) {
+       for (i = last_untagged; i < to_pack.nr_objects; i++) {
                if (objects[i].type != OBJ_COMMIT &&
                    objects[i].type != OBJ_TAG)
                        continue;
        /*
         * And then all the trees.
         */
-       for (i = last_untagged; i < nr_objects; i++) {
+       for (i = last_untagged; i < to_pack.nr_objects; i++) {
                if (objects[i].type != OBJ_TREE)
                        continue;
                add_to_write_order(wo, &wo_end, &objects[i]);
        /*
         * Finally all the rest in really tight order
         */
-       for (i = last_untagged; i < nr_objects; i++) {
+       for (i = last_untagged; i < to_pack.nr_objects; i++) {
                if (!objects[i].filled)
                        add_family_to_write_order(wo, &wo_end, &objects[i]);
        }
  
-       if (wo_end != nr_objects)
-               die("ordered %u objects, expected %"PRIu32, wo_end, nr_objects);
+       if (wo_end != to_pack.nr_objects)
+               die("ordered %u objects, expected %"PRIu32, wo_end, to_pack.nr_objects);
  
        return wo;
  }
  
+ static off_t write_reused_pack(struct sha1file *f)
+ {
+       unsigned char buffer[8192];
+       off_t to_write;
+       int fd;
+       if (!is_pack_valid(reuse_packfile))
+               die("packfile is invalid: %s", reuse_packfile->pack_name);
+       fd = git_open_noatime(reuse_packfile->pack_name);
+       if (fd < 0)
+               die_errno("unable to open packfile for reuse: %s",
+                         reuse_packfile->pack_name);
+       if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
+               die_errno("unable to seek in reused packfile");
+       if (reuse_packfile_offset < 0)
+               reuse_packfile_offset = reuse_packfile->pack_size - 20;
+       to_write = reuse_packfile_offset - sizeof(struct pack_header);
+       while (to_write) {
+               int read_pack = xread(fd, buffer, sizeof(buffer));
+               if (read_pack <= 0)
+                       die_errno("unable to read from reused packfile");
+               if (read_pack > to_write)
+                       read_pack = to_write;
+               sha1write(f, buffer, read_pack);
+               to_write -= read_pack;
+       }
+       close(fd);
+       written += reuse_packfile_objects;
+       return reuse_packfile_offset - sizeof(struct pack_header);
+ }
  static void write_pack_file(void)
  {
        uint32_t i = 0, j;
  
        if (progress > pack_to_stdout)
                progress_state = start_progress("Writing objects", nr_result);
-       written_list = xmalloc(nr_objects * sizeof(*written_list));
+       written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));
        write_order = compute_write_order();
  
        do {
                        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;
+                       assert(pack_to_stdout);
+                       packfile_size = write_reused_pack(f);
+                       offset += packfile_size;
+               }
                nr_written = 0;
-               for (; i < nr_objects; i++) {
+               for (; i < to_pack.nr_objects; i++) {
                        struct object_entry *e = write_order[i];
                        if (write_one(f, e, &offset) == WRITE_ONE_BREAK)
                                break;
                        if (sizeof(tmpname) <= strlen(base_name) + 50)
                                die("pack base name '%s' too long", base_name);
                        snprintf(tmpname, sizeof(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,
                                            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));
+                               stop_progress(&progress_state);
+                               bitmap_writer_show_progress(progress);
+                               bitmap_writer_reuse_bitmaps(&to_pack);
+                               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);
+                               write_bitmap_index = 0;
+                       }
                        free(pack_tmp_name);
                        puts(sha1_to_hex(sha1));
                }
                        written_list[j]->offset = (off_t)-1;
                }
                nr_remaining -= nr_written;
-       } while (nr_remaining && i < nr_objects);
+       } while (nr_remaining && i < to_pack.nr_objects);
  
        free(written_list);
        free(write_order);
                        written, nr_result);
  }
  
- static int locate_object_entry_hash(const unsigned char *sha1)
- {
-       int i;
-       unsigned int ui;
-       memcpy(&ui, sha1, sizeof(unsigned int));
-       i = ui % object_ix_hashsz;
-       while (0 < object_ix[i]) {
-               if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
-                       return i;
-               if (++i == object_ix_hashsz)
-                       i = 0;
-       }
-       return -1 - i;
- }
- static struct object_entry *locate_object_entry(const unsigned char *sha1)
- {
-       int i;
-       if (!object_ix_hashsz)
-               return NULL;
-       i = locate_object_entry_hash(sha1);
-       if (0 <= i)
-               return &objects[object_ix[i]-1];
-       return NULL;
- }
- static void rehash_objects(void)
- {
-       uint32_t i;
-       struct object_entry *oe;
-       object_ix_hashsz = nr_objects * 3;
-       if (object_ix_hashsz < 1024)
-               object_ix_hashsz = 1024;
-       object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
-       memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
-       for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
-               int ix = locate_object_entry_hash(oe->idx.sha1);
-               if (0 <= ix)
-                       continue;
-               ix = -1 - ix;
-               object_ix[ix] = i + 1;
-       }
- }
- static uint32_t name_hash(const char *name)
- {
-       uint32_t c, hash = 0;
-       if (!name)
-               return 0;
-       /*
-        * This effectively just creates a sortable number from the
-        * last sixteen non-whitespace characters. Last characters
-        * count "most", so things that end in ".c" sort together.
-        */
-       while ((c = *name++) != 0) {
-               if (isspace(c))
-                       continue;
-               hash = (hash >> 2) + (c << 24);
-       }
-       return hash;
- }
  static void setup_delta_attr_check(struct git_attr_check *check)
  {
        static struct git_attr *attr_delta;
@@@ -900,42 -898,69 +896,69 @@@ static int no_try_delta(const char *pat
        return 0;
  }
  
- static int add_object_entry(const unsigned char *sha1, enum object_type type,
-                           const char *name, int exclude)
+ /*
+  * When adding an object, check whether we have already added it
+  * to our packing list. If so, we can skip. However, if we are
+  * being asked to excludei t, but the previous mention was to include
+  * it, make sure to adjust its flags and tweak our numbers accordingly.
+  *
+  * As an optimization, we pass out the index position where we would have
+  * found the item, since that saves us from having to look it up again a
+  * few lines later when we want to add the new entry.
+  */
+ static int have_duplicate_entry(const unsigned char *sha1,
+                               int exclude,
+                               uint32_t *index_pos)
  {
        struct object_entry *entry;
-       struct packed_git *p, *found_pack = NULL;
-       off_t found_offset = 0;
-       int ix;
-       uint32_t hash = name_hash(name);
-       ix = nr_objects ? locate_object_entry_hash(sha1) : -1;
-       if (ix >= 0) {
-               if (exclude) {
-                       entry = objects + object_ix[ix] - 1;
-                       if (!entry->preferred_base)
-                               nr_result--;
-                       entry->preferred_base = 1;
-               }
+       entry = packlist_find(&to_pack, sha1, index_pos);
+       if (!entry)
                return 0;
+       if (exclude) {
+               if (!entry->preferred_base)
+                       nr_result--;
+               entry->preferred_base = 1;
        }
  
+       return 1;
+ }
+ /*
+  * Check whether we want the object in the pack (e.g., we do not want
+  * objects found in non-local stores if the "--local" option was used).
+  *
+  * As a side effect of this check, we will find the packed version of this
+  * object, if any. We therefore pass out the pack information to avoid having
+  * to look it up again later.
+  */
+ static int want_object_in_pack(const unsigned char *sha1,
+                              int exclude,
+                              struct packed_git **found_pack,
+                              off_t *found_offset)
+ {
+       struct packed_git *p;
        if (!exclude && local && has_loose_object_nonlocal(sha1))
                return 0;
  
+       *found_pack = NULL;
+       *found_offset = 0;
        for (p = packed_git; p; p = p->next) {
                off_t offset = find_pack_entry_one(sha1, p);
                if (offset) {
-                       if (!found_pack) {
+                       if (!*found_pack) {
                                if (!is_pack_valid(p)) {
                                        warning("packfile %s cannot be accessed", p->pack_name);
                                        continue;
                                }
-                               found_offset = offset;
-                               found_pack = p;
+                               *found_offset = offset;
+                               *found_pack = p;
                        }
                        if (exclude)
-                               break;
+                               return 1;
                        if (incremental)
                                return 0;
                        if (local && !p->pack_local)
                }
        }
  
-       if (nr_objects >= nr_alloc) {
-               nr_alloc = (nr_alloc  + 1024) * 3 / 2;
-               objects = xrealloc(objects, nr_alloc * sizeof(*entry));
-       }
+       return 1;
+ }
+ static void create_object_entry(const unsigned char *sha1,
+                               enum object_type type,
+                               uint32_t hash,
+                               int exclude,
+                               int no_try_delta,
+                               uint32_t index_pos,
+                               struct packed_git *found_pack,
+                               off_t found_offset)
+ {
+       struct object_entry *entry;
  
-       entry = objects + nr_objects++;
-       memset(entry, 0, sizeof(*entry));
-       hashcpy(entry->idx.sha1, sha1);
+       entry = packlist_alloc(&to_pack, sha1, index_pos);
        entry->hash = hash;
        if (type)
                entry->type = type;
                entry->in_pack_offset = found_offset;
        }
  
-       if (object_ix_hashsz * 3 <= nr_objects * 4)
-               rehash_objects();
-       else
-               object_ix[-1 - ix] = nr_objects;
+       entry->no_try_delta = no_try_delta;
+ }
+ static int add_object_entry(const unsigned char *sha1, enum object_type type,
+                           const char *name, int exclude)
+ {
+       struct packed_git *found_pack;
+       off_t found_offset;
+       uint32_t index_pos;
  
-       display_progress(progress_state, nr_objects);
+       if (have_duplicate_entry(sha1, exclude, &index_pos))
+               return 0;
+       if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset))
+               return 0;
  
-       if (name && no_try_delta(name))
-               entry->no_try_delta = 1;
+       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);
+       return 1;
+ }
+ static int add_object_entry_from_bitmap(const unsigned char *sha1,
+                                       enum object_type type,
+                                       int flags, uint32_t name_hash,
+                                       struct packed_git *pack, off_t offset)
+ {
+       uint32_t index_pos;
+       if (have_duplicate_entry(sha1, 0, &index_pos))
+               return 0;
+       create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset);
+       display_progress(progress_state, to_pack.nr_objects);
        return 1;
  }
  
@@@ -1175,7 -1234,7 +1232,7 @@@ static void add_preferred_base_object(c
  {
        struct pbase_tree *it;
        int cmplen;
-       unsigned hash = name_hash(name);
+       unsigned hash = pack_name_hash(name);
  
        if (!num_preferred_base || check_pbase_path(hash))
                return;
@@@ -1327,7 -1386,7 +1384,7 @@@ static void check_object(struct object_
                        break;
                }
  
-               if (base_ref && (base_entry = locate_object_entry(base_ref))) {
+               if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) {
                        /*
                         * If base_ref was set above that means we wish to
                         * reuse delta data, and we even found that base
@@@ -1401,12 -1460,12 +1458,12 @@@ static void get_object_details(void
        uint32_t i;
        struct object_entry **sorted_by_offset;
  
-       sorted_by_offset = xcalloc(nr_objects, sizeof(struct object_entry *));
-       for (i = 0; i < nr_objects; i++)
-               sorted_by_offset[i] = objects + i;
-       qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
+       sorted_by_offset = xcalloc(to_pack.nr_objects, sizeof(struct object_entry *));
+       for (i = 0; i < to_pack.nr_objects; i++)
+               sorted_by_offset[i] = to_pack.objects + i;
+       qsort(sorted_by_offset, to_pack.nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
  
-       for (i = 0; i < nr_objects; i++) {
+       for (i = 0; i < to_pack.nr_objects; i++) {
                struct object_entry *entry = sorted_by_offset[i];
                check_object(entry);
                if (big_file_threshold < entry->size)
@@@ -2030,9 -2089,9 +2087,9 @@@ 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? */
-           locate_object_entry(peeled))      /* object packed? */
+           packlist_find(&to_pack, peeled, NULL))      /* object packed? */
                add_object_entry(sha1, OBJ_TAG, NULL, 0);
        return 0;
  }
@@@ -2055,14 -2114,14 +2112,14 @@@ static void prepare_pack(int window, in
        if (!pack_to_stdout)
                do_check_packed_object_crc = 1;
  
-       if (!nr_objects || !window || !depth)
+       if (!to_pack.nr_objects || !window || !depth)
                return;
  
-       delta_list = xmalloc(nr_objects * sizeof(*delta_list));
+       delta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));
        nr_deltas = n = 0;
  
-       for (i = 0; i < nr_objects; i++) {
-               struct object_entry *entry = objects + i;
+       for (i = 0; i < to_pack.nr_objects; i++) {
+               struct object_entry *entry = to_pack.objects + i;
  
                if (entry->delta)
                        /* This happens if we decided to reuse existing
@@@ -2140,6 -2199,20 +2197,20 @@@ 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;
+               else
+                       write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE;
+       }
+       if (!strcmp(k, "pack.usebitmaps")) {
+               use_bitmap_index = git_config_bool(k, v);
+               return 0;
+       }
        if (!strcmp(k, "pack.threads")) {
                delta_search_threads = git_config_int(k, v);
                if (delta_search_threads < 0)
@@@ -2198,6 -2271,9 +2269,9 @@@ static void show_commit(struct commit *
  {
        add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
        commit->object.flags |= OBJECT_ADDED;
+       if (write_bitmap_index)
+               index_commit_for_bitmap(commit);
  }
  
  static void show_object(struct object *obj,
@@@ -2340,7 -2416,7 +2414,7 @@@ static void loosen_unused_packed_object
  
                for (i = 0; i < p->num_objects; i++) {
                        sha1 = nth_packed_object_sha1(p, i);
-                       if (!locate_object_entry(sha1) &&
+                       if (!packlist_find(&to_pack, sha1, NULL) &&
                                !has_sha1_pack_kept_or_nonlocal(sha1))
                                if (force_object_loose(sha1, p->mtime))
                                        die("unable to force loose object");
        }
  }
  
+ 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(
+                       &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);
+               }
+       }
+       traverse_bitmap_commit_list(&add_object_entry_from_bitmap);
+       return 0;
+ }
  static void get_object_list(int ac, const char **av)
  {
        struct rev_info revs;
                if (*line == '-') {
                        if (!strcmp(line, "--not")) {
                                flags ^= UNINTERESTING;
+                               write_bitmap_index = 0;
                                continue;
                        }
                        die("not a rev '%s'", line);
                        die("bad revision '%s'", line);
        }
  
+       if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
+               return;
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        mark_edges_uninteresting(&revs, show_edge);
@@@ -2504,6 -2607,10 +2605,10 @@@ int cmd_pack_objects(int argc, const ch
                            N_("pack compression level")),
                OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
                            N_("do not hide commits by grafts"), 0),
+               OPT_BOOL(0, "use-bitmap-index", &use_bitmap_index,
+                        N_("use a bitmap index if available to speed up counting objects")),
+               OPT_BOOL(0, "write-bitmap-index", &write_bitmap_index,
+                        N_("write a bitmap index together with the pack index")),
                OPT_END(),
        };
  
        if (keep_unreachable && unpack_unreachable)
                die("--keep-unreachable and --unpack-unreachable are incompatible.");
  
+       if (!use_internal_rev_list || !pack_to_stdout || is_repository_shallow())
+               use_bitmap_index = 0;
+       if (pack_to_stdout || !rev_list_all)
+               write_bitmap_index = 0;
        if (progress && all_progress_implied)
                progress = 2;
  
diff --combined builtin/repack.c
index bb2314c9cb0ce3e01372c6c3a27396931c0143ab,239f278fac9c2be6655458992022b23117ea5020..49f5857627fd616b1019063f3f2d1937b20004fd
@@@ -78,7 -78,7 +78,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");
@@@ -94,7 -94,7 +94,7 @@@
  
  static void remove_redundant_pack(const char *dir_name, const char *base_name)
  {
-       const char *exts[] = {".pack", ".idx", ".keep"};
+       const char *exts[] = {".pack", ".idx", ".keep", ".bitmap"};
        int i;
        struct strbuf buf = STRBUF_INIT;
        size_t plen;
  
  int cmd_repack(int argc, const char **argv, const char *prefix)
  {
-       const char *exts[2] = {".pack", ".idx"};
+       struct {
+               const char *name;
+               unsigned optional:1;
+       } exts[] = {
+               {".pack"},
+               {".idx"},
+               {".bitmap", 1},
+       };
        struct child_process cmd;
        struct string_list_item *item;
        struct argv_array cmd_args = ARGV_ARRAY_INIT;
        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;
        int local = 0;
+       int write_bitmap = -1;
  
        struct option builtin_repack_options[] = {
                OPT_BIT('a', NULL, &pack_everything,
                OPT__QUIET(&quiet, N_("be quiet")),
                OPT_BOOL('l', "local", &local,
                                N_("pass --local to git-pack-objects")),
+               OPT_BOOL('b', "write-bitmap-index", &write_bitmap,
+                               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_END()
        };
        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_bitmap >= 0)
+               argv_array_pushf(&cmd_args, "--%swrite-bitmap-index",
+                                write_bitmap ? "" : "no-");
  
        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");
  
        /*
         */
        failed = 0;
        for_each_string_list_item(item, &names) {
-               for (ext = 0; ext < 2; ext++) {
+               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]);
+                                               item->string, exts[ext].name);
                        if (!file_exists(fname)) {
                                free(fname);
                                continue;
                        }
  
                        fname_old = mkpath("%s/old-%s%s", packdir,
-                                               item->string, exts[ext]);
+                                               item->string, exts[ext].name);
                        if (file_exists(fname_old))
                                if (unlink(fname_old))
                                        failed = 1;
  
        /* Now the ones with the same name are out of the way... */
        for_each_string_list_item(item, &names) {
-               for (ext = 0; ext < 2; ext++) {
+               for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
                        char *fname, *fname_old;
                        struct stat statbuffer;
+                       int exists = 0;
                        fname = mkpathdup("%s/pack-%s%s",
-                                       packdir, item->string, exts[ext]);
+                                       packdir, item->string, exts[ext].name);
                        fname_old = mkpathdup("%s-%s%s",
-                                       packtmp, item->string, exts[ext]);
+                                       packtmp, item->string, exts[ext].name);
                        if (!stat(fname_old, &statbuffer)) {
                                statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
                                chmod(fname_old, statbuffer.st_mode);
+                               exists = 1;
+                       }
+                       if (exists || !exts[ext].optional) {
+                               if (rename(fname_old, fname))
+                                       die_errno(_("renaming '%s' failed"), fname_old);
                        }
-                       if (rename(fname_old, fname))
-                               die_errno(_("renaming '%s' failed"), fname_old);
                        free(fname);
                        free(fname_old);
                }
  
        /* Remove the "old-" files */
        for_each_string_list_item(item, &names) {
-               for (ext = 0; ext < 2; ext++) {
+               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]);
+                                       exts[ext].name);
                        if (remove_path(fname))
                                warning(_("removing '%s' failed"), fname);
                }
diff --combined builtin/rev-list.c
index 0745e2d05330d21152f2aff720d0de338270aa6d,5209255f28c66049b2ec6dc539ceaa7fe339133c..9f92905379d1801a35bfad87bc05002d76dc23f4
@@@ -3,6 -3,8 +3,8 @@@
  #include "diff.h"
  #include "revision.h"
  #include "list-objects.h"
+ #include "pack.h"
+ #include "pack-bitmap.h"
  #include "builtin.h"
  #include "log-tree.h"
  #include "graph.h"
@@@ -257,6 -259,18 +259,18 @@@ static int show_bisect_vars(struct rev_
        return 0;
  }
  
+ static int show_object_fast(
+       const unsigned char *sha1,
+       enum object_type type,
+       int exclude,
+       uint32_t name_hash,
+       struct packed_git *found_pack,
+       off_t found_offset)
+ {
+       fprintf(stdout, "%s\n", sha1_to_hex(sha1));
+       return 1;
+ }
  int cmd_rev_list(int argc, const char **argv, const char *prefix)
  {
        struct rev_info revs;
        int bisect_list = 0;
        int bisect_show_vars = 0;
        int bisect_find_all = 0;
+       int use_bitmap_index = 0;
  
        git_config(git_default_config, NULL);
        init_revisions(&revs, prefix);
                        bisect_show_vars = 1;
                        continue;
                }
+               if (!strcmp(arg, "--use-bitmap-index")) {
+                       use_bitmap_index = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--test-bitmap")) {
+                       test_bitmap_walk(&revs);
+                       return 0;
+               }
                usage(rev_list_usage);
  
        }
                revs.commit_format = CMIT_FMT_RAW;
  
        if ((!revs.commits &&
 -           (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
 +           (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
              !revs.pending.nr)) ||
            revs.diff)
                usage(rev_list_usage);
        if (bisect_list)
                revs.limited = 1;
  
+       if (use_bitmap_index) {
+               if (revs.count && !revs.left_right && !revs.cherry_mark) {
+                       uint32_t commit_count;
+                       if (!prepare_bitmap_walk(&revs)) {
+                               count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
+                               printf("%d\n", commit_count);
+                               return 0;
+                       }
+               } else if (revs.tag_objects && revs.tree_objects && revs.blob_objects) {
+                       if (!prepare_bitmap_walk(&revs)) {
+                               traverse_bitmap_commit_list(&show_object_fast);
+                               return 0;
+                       }
+               }
+       }
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        if (revs.tree_objects)
diff --combined cache.h
index 9f1574421816bfde4236447d1d799c56cbed1671,f2e5aa7dc7d00c045a5b6e664c2fc849320cc93e..db223e8048a50d9f37d523226dfdda05a4f5dd8e
+++ b/cache.h
@@@ -3,7 -3,7 +3,7 @@@
  
  #include "git-compat-util.h"
  #include "strbuf.h"
 -#include "hash.h"
 +#include "hashmap.h"
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
@@@ -130,12 -130,12 +130,12 @@@ struct stat_data 
  };
  
  struct cache_entry {
 +      struct hashmap_entry ent;
        struct stat_data ce_stat_data;
        unsigned int ce_mode;
        unsigned int ce_flags;
        unsigned int ce_namelen;
        unsigned char sha1[20];
 -      struct cache_entry *next;
        char name[FLEX_ARRAY]; /* more */
  };
  
  #define CE_ADDED             (1 << 19)
  
  #define CE_HASHED            (1 << 20)
 -#define CE_UNHASHED          (1 << 21)
  #define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
  #define CE_CONFLICTED        (1 << 23)
  
@@@ -194,18 -195,17 +194,18 @@@ struct pathspec
   * Copy the sha1 and stat state of a cache entry from one to
   * another. But we never change the name, or the hash state!
   */
 -#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
  static inline void copy_cache_entry(struct cache_entry *dst,
                                    const struct cache_entry *src)
  {
 -      unsigned int state = dst->ce_flags & CE_STATE_MASK;
 +      unsigned int state = dst->ce_flags & CE_HASHED;
  
        /* Don't copy hash chain and name */
 -      memcpy(dst, src, offsetof(struct cache_entry, next));
 +      memcpy(&dst->ce_stat_data, &src->ce_stat_data,
 +                      offsetof(struct cache_entry, name) -
 +                      offsetof(struct cache_entry, ce_stat_data));
  
        /* Restore the hash state */
 -      dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
 +      dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
  }
  
  static inline unsigned create_ce_flags(unsigned stage)
@@@ -277,8 -277,8 +277,8 @@@ struct index_state 
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
                 initialized : 1;
 -      struct hash_table name_hash;
 -      struct hash_table dir_hash;
 +      struct hashmap name_hash;
 +      struct hashmap dir_hash;
  };
  
  extern struct index_state the_index;
@@@ -316,6 -316,7 +316,6 @@@ extern void free_name_hash(struct index
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
  #define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
  #define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
 -#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
  #define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
  #define resolve_undo_clear() resolve_undo_clear_index(&the_index)
  #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
@@@ -353,7 -354,6 +353,7 @@@ static inline enum object_type object_t
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
  #define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
 +#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
  #define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
  #define CONFIG_ENVIRONMENT "GIT_CONFIG"
  #define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
@@@ -398,6 -398,7 +398,6 @@@ extern int is_bare_repository(void)
  extern int is_inside_git_dir(void);
  extern char *git_work_tree_cfg;
  extern int is_inside_work_tree(void);
 -extern int have_git_dir(void);
  extern const char *get_git_dir(void);
  extern int is_git_directory(const char *path);
  extern char *get_object_directory(void);
@@@ -466,6 -467,7 +466,6 @@@ extern int unmerged_index(const struct 
  extern int verify_path(const char *path);
  extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
  extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
 -extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
  extern int index_name_pos(const struct index_state *, const char *name, int namelen);
  #define ADD_CACHE_OK_TO_ADD 1         /* Ok to add */
  #define ADD_CACHE_OK_TO_REPLACE 2     /* Ok to replace file/directory */
@@@ -485,9 -487,8 +485,9 @@@ extern int remove_file_from_index(struc
  #define ADD_CACHE_IMPLICIT_DOT 32     /* internal to "git add -u/-A" */
  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
  extern int add_file_to_index(struct index_state *, const char *path, int flags);
 -extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
 +extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
 +extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
  extern int index_name_is_other(const struct index_state *, const char *, int);
  extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
  
  #define CE_MATCH_RACY_IS_DIRTY                02
  /* do stat comparison even if CE_SKIP_WORKTREE is true */
  #define CE_MATCH_IGNORE_SKIP_WORKTREE 04
 +/* ignore non-existent files during stat update  */
 +#define CE_MATCH_IGNORE_MISSING               0x08
 +/* enable stat refresh */
 +#define CE_MATCH_REFRESH              0x10
  extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  
 -extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
 -
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
  extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
@@@ -738,29 -737,8 +738,29 @@@ enum sharedrepo 
  };
  int git_config_perm(const char *var, const char *value);
  int adjust_shared_perm(const char *path);
 -int safe_create_leading_directories(char *path);
 -int safe_create_leading_directories_const(const char *path);
 +
 +/*
 + * Create the directory containing the named path, using care to be
 + * somewhat safe against races.  Return one of the scld_error values
 + * to indicate success/failure.
 + *
 + * SCLD_VANISHED indicates that one of the ancestor directories of the
 + * path existed at one point during the function call and then
 + * suddenly vanished, probably because another process pruned the
 + * directory while we were working.  To be robust against this kind of
 + * race, callers might want to try invoking the function again when it
 + * returns SCLD_VANISHED.
 + */
 +enum scld_error {
 +      SCLD_OK = 0,
 +      SCLD_FAILED = -1,
 +      SCLD_PERMS = -2,
 +      SCLD_EXISTS = -3,
 +      SCLD_VANISHED = -4
 +};
 +enum scld_error safe_create_leading_directories(char *path);
 +enum scld_error safe_create_leading_directories_const(const char *path);
 +
  int mkdir_in_gitdir(const char *path);
  extern void home_config_paths(char **global, char **xdg, char *file);
  extern char *expand_user_path(const char *path);
@@@ -773,7 -751,6 +773,7 @@@ int is_directory(const char *)
  const char *real_path(const char *path);
  const char *real_path_if_valid(const char *path);
  const char *absolute_path(const char *path);
 +const char *remove_leading_path(const char *in, const char *prefix);
  const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
  int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
  int normalize_path_copy(char *dst, const char *src);
@@@ -783,11 -760,11 +783,11 @@@ int daemon_avoid_alias(const char *path
  int offset_1st_component(const char *path);
  
  /* object replacement */
 -#define READ_SHA1_FILE_REPLACE 1
 +#define LOOKUP_REPLACE_OBJECT 1
  extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
 -      return read_sha1_file_extended(sha1, type, size, READ_SHA1_FILE_REPLACE);
 +      return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
  }
  extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
  static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
                return sha1;
        return do_lookup_replace_object(sha1);
  }
 +static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
 +{
 +      if (!(flag & LOOKUP_REPLACE_OBJECT))
 +              return sha1;
 +      return lookup_replace_object(sha1);
 +}
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
@@@ -809,6 -780,7 +809,7 @@@ extern int hash_sha1_file(const void *b
  extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
+ extern int git_open_noatime(const char *name);
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
  extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
@@@ -916,12 -888,9 +917,12 @@@ extern int dwim_log(const char *str, in
  extern int interpret_branch_name(const char *str, int len, struct strbuf *);
  extern int get_sha1_mb(const char *str, unsigned char *sha1);
  
 -extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
 -extern const char *ref_rev_parse_rules[];
 -#define ref_fetch_rules ref_rev_parse_rules
 +/*
 + * Return true iff abbrev_name is a possible abbreviation for
 + * full_name according to the rules defined by ref_rev_parse_rules in
 + * refs.c.
 + */
 +extern int refname_match(const char *abbrev_name, const char *full_name);
  
  extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
  extern int validate_headref(const char *ref);
@@@ -1007,7 -976,6 +1008,7 @@@ struct checkout 
                 refresh_cache:1;
  };
  
 +#define TEMPORARY_FILENAME_LENGTH 25
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
  
  struct cache_def {
@@@ -1106,7 -1074,6 +1107,7 @@@ struct object_info 
        enum object_type *typep;
        unsigned long *sizep;
        unsigned long *disk_sizep;
 +      unsigned char *delta_base_sha1;
  
        /* Response */
        enum {
                } packed;
        } u;
  };
 -extern int sha1_object_info_extended(const unsigned char *, struct object_info *);
 +extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
  
  /* Dumb servers support */
  extern int update_server_info(int);
@@@ -1269,8 -1236,6 +1270,8 @@@ __attribute__((format (printf, 2, 3))
  extern void trace_argv_printf(const char **argv, const char *format, ...);
  extern void trace_repo_setup(const char *prefix);
  extern int trace_want(const char *key);
 +__attribute__((format (printf, 2, 3)))
 +extern void trace_printf_key(const char *key, const char *fmt, ...);
  extern void trace_strbuf(const char *key, const struct strbuf *buf);
  
  void packet_trace_identity(const char *prog);
diff --combined pack-write.c
index 605d01b25cbd9d796810f8aa810894a2c198da28,6203d37ac5efed2ef02b1d694b30bd0ee4e96d03..9b8308b7594263c4900a6d75c18b91cea959fd70
@@@ -44,13 -44,14 +44,13 @@@ static int need_large_offset(off_t offs
   */
  const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects,
                           int nr_objects, const struct pack_idx_option *opts,
 -                         unsigned char *sha1)
 +                         const unsigned char *sha1)
  {
        struct sha1file *f;
        struct pack_idx_entry **sorted_by_sha, **list, **last;
        off_t last_obj_offset = 0;
        uint32_t array[256];
        int i, fd;
 -      git_SHA_CTX ctx;
        uint32_t index_version;
  
        if (nr_objects) {
        }
        sha1write(f, array, 256 * 4);
  
 -      /* compute the SHA1 hash of sorted object names. */
 -      git_SHA1_Init(&ctx);
 -
        /*
         * Write the actual SHA1 entries..
         */
                        sha1write(f, &offset, 4);
                }
                sha1write(f, obj->sha1, 20);
 -              git_SHA1_Update(&ctx, obj->sha1, 20);
                if ((opts->flags & WRITE_IDX_STRICT) &&
                    (i && !hashcmp(list[-2]->sha1, obj->sha1)))
                        die("The same object %s appears twice in the pack",
        sha1write(f, sha1, 20);
        sha1close(f, NULL, ((opts->flags & WRITE_IDX_VERIFY)
                            ? CSUM_CLOSE : CSUM_FSYNC));
 -      git_SHA1_Final(sha1, &ctx);
        return index_name;
  }
  
@@@ -183,7 -189,8 +183,7 @@@ off_t write_pack_header(struct sha1fil
        hdr.hdr_signature = htonl(PACK_SIGNATURE);
        hdr.hdr_version = htonl(PACK_VERSION);
        hdr.hdr_entries = htonl(nr_entries);
 -      if (sha1write(f, &hdr, sizeof(hdr)))
 -              return 0;
 +      sha1write(f, &hdr, sizeof(hdr));
        return sizeof(hdr);
  }
  
@@@ -364,5 -371,7 +364,7 @@@ void finish_tmp_packfile(char *name_buf
        if (rename(idx_tmp_name, name_buffer))
                die_errno("unable to rename temporary index file");
  
+       *end_of_name_prefix = '\0';
        free((void *)idx_tmp_name);
  }
diff --combined read-cache.c
index 6d8ee3a792d09aa347da275770aa775e6cd9eb33,422187262d8f03c2c32108c4f3cc046bb404214c..fb440b4d9d1aa002ebc760e4fa4e0f0d028fd868
@@@ -15,8 -15,7 +15,8 @@@
  #include "strbuf.h"
  #include "varint.h"
  
 -static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 +static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
 +                                             unsigned int options);
  
  /* Mask for the name length in ce_flags in the on-disk index */
  
@@@ -48,7 -47,6 +48,7 @@@ static void replace_index_entry(struct 
        struct cache_entry *old = istate->cache[nr];
  
        remove_name_hash(istate, old);
 +      free(old);
        set_index_entry(istate, nr, ce);
        istate->cache_changed = 1;
  }
@@@ -60,7 -58,7 +60,7 @@@ void rename_index_entry_at(struct index
  
        new = xmalloc(cache_entry_size(namelen));
        copy_cache_entry(new, old);
 -      new->ce_flags &= ~CE_STATE_MASK;
 +      new->ce_flags &= ~CE_HASHED;
        new->ce_namelen = namelen;
        memcpy(new->name, new_name, namelen + 1);
  
@@@ -480,7 -478,6 +480,7 @@@ int remove_index_entry_at(struct index_
  
        record_resolve_undo(istate, ce);
        remove_name_hash(istate, ce);
 +      free(ce);
        istate->cache_changed = 1;
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
@@@ -502,10 -499,8 +502,10 @@@ void remove_marked_cache_entries(struc
        unsigned int i, j;
  
        for (i = j = 0; i < istate->cache_nr; i++) {
 -              if (ce_array[i]->ce_flags & CE_REMOVE)
 +              if (ce_array[i]->ce_flags & CE_REMOVE) {
                        remove_name_hash(istate, ce_array[i]);
 +                      free(ce_array[i]);
 +              }
                else
                        ce_array[j++] = ce_array[i];
        }
@@@ -584,7 -579,7 +584,7 @@@ static struct cache_entry *create_alias
        return new;
  }
  
 -static void record_intent_to_add(struct cache_entry *ce)
 +void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
  {
        unsigned char sha1[20];
        if (write_sha1_file("", 0, blob_type, sha1))
@@@ -670,7 -665,7 +670,7 @@@ int add_to_index(struct index_state *is
                if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
                        return error("unable to index file %s", path);
        } else
 -              record_intent_to_add(ce);
 +              set_object_name_for_intent_to_add_entry(ce);
  
        if (ignore_case && alias && different_name(ce, alias))
                ce = create_alias_ce(ce, alias);
@@@ -701,7 -696,7 +701,7 @@@ int add_file_to_index(struct index_stat
  
  struct cache_entry *make_cache_entry(unsigned int mode,
                const unsigned char *sha1, const char *path, int stage,
 -              int refresh)
 +              unsigned int refresh_options)
  {
        int size, len;
        struct cache_entry *ce;
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
  
 -      if (refresh)
 -              return refresh_cache_entry(ce, 0);
 -
 -      return ce;
 +      return refresh_cache_entry(ce, refresh_options);
  }
  
  int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
        return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
  }
  
 -int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)
 -{
 -      return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);
 -}
 -
  /*
   * We fundamentally don't like some paths: we don't want
   * dot or dot-dot anywhere, and for obvious reasons don't
@@@ -1026,12 -1029,10 +1026,12 @@@ static struct cache_entry *refresh_cach
        struct stat st;
        struct cache_entry *updated;
        int changed, size;
 +      int refresh = options & CE_MATCH_REFRESH;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
        int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
 +      int ignore_missing = options & CE_MATCH_IGNORE_MISSING;
  
 -      if (ce_uptodate(ce))
 +      if (!refresh || ce_uptodate(ce))
                return ce;
  
        /*
        }
  
        if (lstat(ce->name, &st) < 0) {
 +              if (ignore_missing && errno == ENOENT)
 +                      return ce;
                if (err)
                        *err = errno;
                return NULL;
@@@ -1128,9 -1127,7 +1128,9 @@@ int refresh_index(struct index_state *i
        int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
        int first = 1;
        int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
 -      unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
 +      unsigned int options = (CE_MATCH_REFRESH |
 +                              (really ? CE_MATCH_IGNORE_VALID : 0) |
 +                              (not_new ? CE_MATCH_IGNORE_MISSING : 0));
        const char *modified_fmt;
        const char *deleted_fmt;
        const char *typechange_fmt;
                if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
                        continue;
  
 -              if (pathspec &&
 -                  !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen))
 +              if (pathspec && !ce_path_match(ce, pathspec, seen))
                        filtered = 1;
  
                if (ce_stage(ce)) {
                if (!new) {
                        const char *fmt;
  
 -                      if (not_new && cache_errno == ENOENT)
 -                              continue;
                        if (really && cache_errno == EINVAL) {
                                /* If we are doing --really-refresh that
                                 * means the index is not valid anymore.
        return has_errors;
  }
  
 -static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
 +static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
 +                                             unsigned int options)
  {
 -      return refresh_cache_ent(&the_index, ce, really, NULL, NULL);
 +      return refresh_cache_ent(&the_index, ce, options, NULL, NULL);
  }
  
  
@@@ -1314,26 -1313,6 +1314,6 @@@ int read_index(struct index_state *ista
        return read_index_from(istate, get_index_file());
  }
  
- #ifndef NEEDS_ALIGNED_ACCESS
- #define ntoh_s(var) ntohs(var)
- #define ntoh_l(var) ntohl(var)
- #else
- static inline uint16_t ntoh_s_force_align(void *p)
- {
-       uint16_t x;
-       memcpy(&x, p, sizeof(x));
-       return ntohs(x);
- }
- static inline uint32_t ntoh_l_force_align(void *p)
- {
-       uint32_t x;
-       memcpy(&x, p, sizeof(x));
-       return ntohl(x);
- }
- #define ntoh_s(var) ntoh_s_force_align(&(var))
- #define ntoh_l(var) ntoh_l_force_align(&(var))
- #endif
  static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
                                                   unsigned int flags,
                                                   const char *name,
  {
        struct cache_entry *ce = xmalloc(cache_entry_size(len));
  
-       ce->ce_stat_data.sd_ctime.sec = ntoh_l(ondisk->ctime.sec);
-       ce->ce_stat_data.sd_mtime.sec = ntoh_l(ondisk->mtime.sec);
-       ce->ce_stat_data.sd_ctime.nsec = ntoh_l(ondisk->ctime.nsec);
-       ce->ce_stat_data.sd_mtime.nsec = ntoh_l(ondisk->mtime.nsec);
-       ce->ce_stat_data.sd_dev   = ntoh_l(ondisk->dev);
-       ce->ce_stat_data.sd_ino   = ntoh_l(ondisk->ino);
-       ce->ce_mode  = ntoh_l(ondisk->mode);
-       ce->ce_stat_data.sd_uid   = ntoh_l(ondisk->uid);
-       ce->ce_stat_data.sd_gid   = ntoh_l(ondisk->gid);
-       ce->ce_stat_data.sd_size  = ntoh_l(ondisk->size);
+       ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
+       ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
+       ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
+       ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
+       ce->ce_stat_data.sd_dev   = get_be32(&ondisk->dev);
+       ce->ce_stat_data.sd_ino   = get_be32(&ondisk->ino);
+       ce->ce_mode  = get_be32(&ondisk->mode);
+       ce->ce_stat_data.sd_uid   = get_be32(&ondisk->uid);
+       ce->ce_stat_data.sd_gid   = get_be32(&ondisk->gid);
+       ce->ce_stat_data.sd_size  = get_be32(&ondisk->size);
        ce->ce_flags = flags & ~CE_NAMEMASK;
        ce->ce_namelen = len;
        hashcpy(ce->sha1, ondisk->sha1);
@@@ -1390,14 -1369,14 +1370,14 @@@ static struct cache_entry *create_from_
        unsigned int flags;
  
        /* On-disk flags are just 16 bits */
-       flags = ntoh_s(ondisk->flags);
+       flags = get_be16(&ondisk->flags);
        len = flags & CE_NAMEMASK;
  
        if (flags & CE_EXTENDED) {
                struct ondisk_cache_entry_extended *ondisk2;
                int extended_flags;
                ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
-               extended_flags = ntoh_s(ondisk2->flags2) << 16;
+               extended_flags = get_be16(&ondisk2->flags2) << 16;
                /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
                if (extended_flags & ~CE_EXTENDED_FLAGS)
                        die("Unknown index entry format %08x", extended_flags);
@@@ -1895,7 -1874,7 +1875,7 @@@ int read_index_unmerged(struct index_st
                new_ce->ce_mode = ce->ce_mode;
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
 -                                   ce->name);
 +                                   new_ce->name);
                i = index_name_pos(istate, new_ce->name, len);
        }
        return unmerged;
diff --combined revision.c
index 61be08754af91a32f9c7729f2e5223c592faf451,cddd6051e307cf5455e41cdd404008d5a1967f84..bd027bc0152a59ac0c4584ab752ff70bee5abbfa
@@@ -16,7 -16,6 +16,7 @@@
  #include "line-log.h"
  #include "mailmap.h"
  #include "commit-slab.h"
 +#include "dir.h"
  
  volatile show_early_output_fn_t show_early_output;
  
@@@ -105,12 -104,17 +105,12 @@@ static void mark_blob_uninteresting(str
        blob->object.flags |= UNINTERESTING;
  }
  
 -void mark_tree_uninteresting(struct tree *tree)
 +static void mark_tree_contents_uninteresting(struct tree *tree)
  {
        struct tree_desc desc;
        struct name_entry entry;
        struct object *obj = &tree->object;
  
 -      if (!tree)
 -              return;
 -      if (obj->flags & UNINTERESTING)
 -              return;
 -      obj->flags |= UNINTERESTING;
        if (!has_sha1_file(obj->sha1))
                return;
        if (parse_tree(tree) < 0)
        free_tree_buffer(tree);
  }
  
 +void mark_tree_uninteresting(struct tree *tree)
 +{
 +      struct object *obj = &tree->object;
 +
 +      if (!tree)
 +              return;
 +      if (obj->flags & UNINTERESTING)
 +              return;
 +      obj->flags |= UNINTERESTING;
 +      mark_tree_contents_uninteresting(tree);
 +}
 +
  void mark_parents_uninteresting(struct commit *commit)
  {
        struct commit_list *parents = NULL, *l;
@@@ -284,7 -276,6 +284,7 @@@ static struct commit *handle_commit(str
                                return NULL;
                        die("bad object %s", sha1_to_hex(tag->tagged->sha1));
                }
 +              object->flags |= flags;
        }
  
        /*
                if (parse_commit(commit) < 0)
                        die("unable to parse commit %s", name);
                if (flags & UNINTERESTING) {
 -                      commit->object.flags |= UNINTERESTING;
                        mark_parents_uninteresting(commit);
                        revs->limited = 1;
                }
                if (!revs->tree_objects)
                        return NULL;
                if (flags & UNINTERESTING) {
 -                      mark_tree_uninteresting(tree);
 +                      mark_tree_contents_uninteresting(tree);
                        return NULL;
                }
                add_pending_object(revs, object, "");
         * Blob object? You know the drill by now..
         */
        if (object->type == OBJ_BLOB) {
 -              struct blob *blob = (struct blob *)object;
                if (!revs->blob_objects)
                        return NULL;
 -              if (flags & UNINTERESTING) {
 -                      mark_blob_uninteresting(blob);
 +              if (flags & UNINTERESTING)
                        return NULL;
 -              }
                add_pending_object(revs, object, "");
                return NULL;
        }
@@@ -497,14 -492,24 +497,14 @@@ static int rev_compare_tree(struct rev_
  static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
  {
        int retval;
 -      void *tree;
 -      unsigned long size;
 -      struct tree_desc empty, real;
        struct tree *t1 = commit->tree;
  
        if (!t1)
                return 0;
  
 -      tree = read_object_with_reference(t1->object.sha1, tree_type, &size, NULL);
 -      if (!tree)
 -              return 0;
 -      init_tree_desc(&real, tree, size);
 -      init_tree_desc(&empty, "", 0);
 -
        tree_difference = REV_TREE_SAME;
        DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
 -      retval = diff_tree(&empty, &real, "", &revs->pruning);
 -      free(tree);
 +      retval = diff_tree_sha1(NULL, t1->object.sha1, "", &revs->pruning);
  
        return retval >= 0 && (tree_difference == REV_TREE_SAME);
  }
@@@ -774,6 -779,10 +774,10 @@@ static int add_parents_to_list(struct r
                return 0;
        commit->object.flags |= ADDED;
  
+       if (revs->include_check &&
+           !revs->include_check(commit, revs->include_check_data))
+               return 0;
        /*
         * If the commit is uninteresting, don't try to
         * prune parents - we want the maximal uninteresting
@@@ -1175,28 -1184,11 +1179,28 @@@ struct all_refs_cb 
        const char *name_for_errormsg;
  };
  
 +int ref_excluded(struct string_list *ref_excludes, const char *path)
 +{
 +      struct string_list_item *item;
 +
 +      if (!ref_excludes)
 +              return 0;
 +      for_each_string_list_item(item, ref_excludes) {
 +              if (!fnmatch(item->string, path, 0))
 +                      return 1;
 +      }
 +      return 0;
 +}
 +
  static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  {
        struct all_refs_cb *cb = cb_data;
 -      struct object *object = get_reference(cb->all_revs, path, sha1,
 -                                            cb->all_flags);
 +      struct object *object;
 +
 +      if (ref_excluded(cb->all_revs->ref_excludes, path))
 +          return 0;
 +
 +      object = get_reference(cb->all_revs, path, sha1, cb->all_flags);
        add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
        add_pending_sha1(cb->all_revs, path, sha1, cb->all_flags);
        return 0;
@@@ -1209,24 -1201,6 +1213,24 @@@ static void init_all_refs_cb(struct all
        cb->all_flags = flags;
  }
  
 +void clear_ref_exclusion(struct string_list **ref_excludes_p)
 +{
 +      if (*ref_excludes_p) {
 +              string_list_clear(*ref_excludes_p, 0);
 +              free(*ref_excludes_p);
 +      }
 +      *ref_excludes_p = NULL;
 +}
 +
 +void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)
 +{
 +      if (!*ref_excludes_p) {
 +              *ref_excludes_p = xcalloc(1, sizeof(**ref_excludes_p));
 +              (*ref_excludes_p)->strdup_strings = 1;
 +      }
 +      string_list_append(*ref_excludes_p, exclude);
 +}
 +
  static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,
                int (*for_each)(const char *, each_ref_fn, void *))
  {
@@@ -1391,7 -1365,7 +1395,7 @@@ static void prepare_show_merge(struct r
                const struct cache_entry *ce = active_cache[i];
                if (!ce_stage(ce))
                        continue;
 -              if (ce_path_match(ce, &revs->prune_data)) {
 +              if (ce_path_match(ce, &revs->prune_data, NULL)) {
                        prune_num++;
                        prune = xrealloc(prune, sizeof(*prune) * prune_num);
                        prune[prune_num-2] = ce->name;
                        i++;
        }
        free_pathspec(&revs->prune_data);
 -      parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC, 0, "", prune);
 +      parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
 +                     PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH, "", prune);
        revs->limited = 1;
  }
  
@@@ -1450,40 -1423,26 +1454,40 @@@ int handle_revision_arg(const char *arg
                }
                if (!get_sha1_committish(this, from_sha1) &&
                    !get_sha1_committish(next, sha1)) {
 -                      struct commit *a, *b;
 -                      struct commit_list *exclude;
 -
 -                      a = lookup_commit_reference(from_sha1);
 -                      b = lookup_commit_reference(sha1);
 -                      if (!a || !b) {
 -                              if (revs->ignore_missing)
 -                                      return 0;
 -                              die(symmetric ?
 -                                  "Invalid symmetric difference expression %s...%s" :
 -                                  "Invalid revision range %s..%s",
 -                                  arg, next);
 -                      }
 +                      struct object *a_obj, *b_obj;
  
                        if (!cant_be_filename) {
                                *dotdot = '.';
                                verify_non_filename(revs->prefix, arg);
                        }
  
 -                      if (symmetric) {
 +                      a_obj = parse_object(from_sha1);
 +                      b_obj = parse_object(sha1);
 +                      if (!a_obj || !b_obj) {
 +                      missing:
 +                              if (revs->ignore_missing)
 +                                      return 0;
 +                              die(symmetric
 +                                  ? "Invalid symmetric difference expression %s"
 +                                  : "Invalid revision range %s", arg);
 +                      }
 +
 +                      if (!symmetric) {
 +                              /* just A..B */
 +                              a_flags = flags_exclude;
 +                      } else {
 +                              /* A...B -- find merge bases between the two */
 +                              struct commit *a, *b;
 +                              struct commit_list *exclude;
 +
 +                              a = (a_obj->type == OBJ_COMMIT
 +                                   ? (struct commit *)a_obj
 +                                   : lookup_commit_reference(a_obj->sha1));
 +                              b = (b_obj->type == OBJ_COMMIT
 +                                   ? (struct commit *)b_obj
 +                                   : lookup_commit_reference(b_obj->sha1));
 +                              if (!a || !b)
 +                                      goto missing;
                                exclude = get_merge_bases(a, b, 1);
                                add_rev_cmdline_list(revs, exclude,
                                                     REV_CMD_MERGE_BASE,
                                add_pending_commit_list(revs, exclude,
                                                        flags_exclude);
                                free_commit_list(exclude);
 +
                                a_flags = flags | SYMMETRIC_LEFT;
 -                      } else
 -                              a_flags = flags_exclude;
 -                      a->object.flags |= a_flags;
 -                      b->object.flags |= flags;
 -                      add_rev_cmdline(revs, &a->object, this,
 +                      }
 +
 +                      a_obj->flags |= a_flags;
 +                      b_obj->flags |= flags;
 +                      add_rev_cmdline(revs, a_obj, this,
                                        REV_CMD_LEFT, a_flags);
 -                      add_rev_cmdline(revs, &b->object, next,
 +                      add_rev_cmdline(revs, b_obj, next,
                                        REV_CMD_RIGHT, flags);
 -                      add_pending_object(revs, &a->object, this);
 -                      add_pending_object(revs, &b->object, next);
 +                      add_pending_object(revs, a_obj, this);
 +                      add_pending_object(revs, b_obj, next);
                        return 0;
                }
                *dotdot = '.';
@@@ -1549,7 -1507,7 +1553,7 @@@ struct cmdline_pathspec 
  static void append_prune_data(struct cmdline_pathspec *prune, const char **av)
  {
        while (*av) {
 -              ALLOC_GROW(prune->path, prune->nr+1, prune->alloc);
 +              ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);
                prune->path[prune->nr++] = *(av++);
        }
  }
@@@ -1561,7 -1519,7 +1565,7 @@@ static void read_pathspec_from_stdin(st
                int len = sb->len;
                if (len && sb->buf[len - 1] == '\n')
                        sb->buf[--len] = '\0';
 -              ALLOC_GROW(prune->path, prune->nr+1, prune->alloc);
 +              ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);
                prune->path[prune->nr++] = xstrdup(sb->buf);
        }
  }
@@@ -1622,9 -1580,9 +1626,9 @@@ static int handle_revision_opt(struct r
            !strcmp(arg, "--tags") || !strcmp(arg, "--remotes") ||
            !strcmp(arg, "--reflog") || !strcmp(arg, "--not") ||
            !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
 -          !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
 -          !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
 -          !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
 +          !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
 +          starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
 +          starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
        {
                unkv[(*unkc)++] = arg;
                return 1;
                revs->max_count = atoi(argv[1]);
                revs->no_walk = 0;
                return 2;
 -      } else if (!prefixcmp(arg, "-n")) {
 +      } else if (starts_with(arg, "-n")) {
                revs->max_count = atoi(arg + 2);
                revs->no_walk = 0;
        } else if ((argcount = parse_long_opt("max-age", argv, &optarg))) {
        } else if (!strcmp(arg, "--author-date-order")) {
                revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
                revs->topo_order = 1;
 -      } else if (!prefixcmp(arg, "--early-output")) {
 +      } else if (starts_with(arg, "--early-output")) {
                int count = 100;
                switch (arg[14]) {
                case '=':
                revs->min_parents = 2;
        } else if (!strcmp(arg, "--no-merges")) {
                revs->max_parents = 1;
 -      } else if (!prefixcmp(arg, "--min-parents=")) {
 +      } else if (starts_with(arg, "--min-parents=")) {
                revs->min_parents = atoi(arg+14);
 -      } else if (!prefixcmp(arg, "--no-min-parents")) {
 +      } else if (starts_with(arg, "--no-min-parents")) {
                revs->min_parents = 0;
 -      } else if (!prefixcmp(arg, "--max-parents=")) {
 +      } else if (starts_with(arg, "--max-parents=")) {
                revs->max_parents = atoi(arg+14);
 -      } else if (!prefixcmp(arg, "--no-max-parents")) {
 +      } else if (starts_with(arg, "--no-max-parents")) {
                revs->max_parents = -1;
        } else if (!strcmp(arg, "--boundary")) {
                revs->boundary = 1;
                revs->verify_objects = 1;
        } else if (!strcmp(arg, "--unpacked")) {
                revs->unpacked = 1;
 -      } else if (!prefixcmp(arg, "--unpacked=")) {
 +      } else if (starts_with(arg, "--unpacked=")) {
                die("--unpacked=<packfile> no longer supported.");
        } else if (!strcmp(arg, "-r")) {
                revs->diff = 1;
                revs->verbose_header = 1;
                revs->pretty_given = 1;
                get_commit_format(arg+8, revs);
 -      } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) {
 +      } else if (starts_with(arg, "--pretty=") || starts_with(arg, "--format=")) {
                /*
                 * Detached form ("--pretty X" as opposed to "--pretty=X")
                 * not allowed, since the argument is optional.
                revs->notes_opt.use_default_notes = 1;
        } else if (!strcmp(arg, "--show-signature")) {
                revs->show_signature = 1;
 -      } else if (!prefixcmp(arg, "--show-notes=") ||
 -                 !prefixcmp(arg, "--notes=")) {
 +      } else if (starts_with(arg, "--show-notes=") ||
 +                 starts_with(arg, "--notes=")) {
                struct strbuf buf = STRBUF_INIT;
                revs->show_notes = 1;
                revs->show_notes_given = 1;
 -              if (!prefixcmp(arg, "--show-notes")) {
 +              if (starts_with(arg, "--show-notes")) {
                        if (revs->notes_opt.use_default_notes < 0)
                                revs->notes_opt.use_default_notes = 1;
                        strbuf_addstr(&buf, arg+13);
                revs->abbrev = 0;
        } else if (!strcmp(arg, "--abbrev")) {
                revs->abbrev = DEFAULT_ABBREV;
 -      } else if (!prefixcmp(arg, "--abbrev=")) {
 +      } else if (starts_with(arg, "--abbrev=")) {
                revs->abbrev = strtoul(arg + 9, NULL, 10);
                if (revs->abbrev < MINIMUM_ABBREV)
                        revs->abbrev = MINIMUM_ABBREV;
@@@ -1999,51 -1957,40 +2003,51 @@@ static int handle_revision_pseudo_opt(c
        if (!strcmp(arg, "--all")) {
                handle_refs(submodule, revs, *flags, for_each_ref_submodule);
                handle_refs(submodule, revs, *flags, head_ref_submodule);
 +              clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--branches")) {
                handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
 +              clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--bisect")) {
                handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
                handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
                revs->bisect = 1;
        } else if (!strcmp(arg, "--tags")) {
                handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);
 +              clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--remotes")) {
                handle_refs(submodule, revs, *flags, for_each_remote_ref_submodule);
 +              clear_ref_exclusion(&revs->ref_excludes);
        } else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
                struct all_refs_cb cb;
                init_all_refs_cb(&cb, revs, *flags);
                for_each_glob_ref(handle_one_ref, optarg, &cb);
 +              clear_ref_exclusion(&revs->ref_excludes);
                return argcount;
 -      } else if (!prefixcmp(arg, "--branches=")) {
 +      } else if ((argcount = parse_long_opt("exclude", argv, &optarg))) {
 +              add_ref_exclusion(&revs->ref_excludes, optarg);
 +              return argcount;
 +      } else if (starts_with(arg, "--branches=")) {
                struct all_refs_cb cb;
                init_all_refs_cb(&cb, revs, *flags);
                for_each_glob_ref_in(handle_one_ref, arg + 11, "refs/heads/", &cb);
 -      } else if (!prefixcmp(arg, "--tags=")) {
 +              clear_ref_exclusion(&revs->ref_excludes);
 +      } else if (starts_with(arg, "--tags=")) {
                struct all_refs_cb cb;
                init_all_refs_cb(&cb, revs, *flags);
                for_each_glob_ref_in(handle_one_ref, arg + 7, "refs/tags/", &cb);
 -      } else if (!prefixcmp(arg, "--remotes=")) {
 +              clear_ref_exclusion(&revs->ref_excludes);
 +      } else if (starts_with(arg, "--remotes=")) {
                struct all_refs_cb cb;
                init_all_refs_cb(&cb, revs, *flags);
                for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb);
 +              clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--reflog")) {
                handle_reflog(revs, *flags);
        } else if (!strcmp(arg, "--not")) {
                *flags ^= UNINTERESTING | BOTTOM;
        } else if (!strcmp(arg, "--no-walk")) {
                revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
 -      } else if (!prefixcmp(arg, "--no-walk=")) {
 +      } else if (starts_with(arg, "--no-walk=")) {
                /*
                 * Detached form ("--no-walk X" as opposed to "--no-walk=X")
                 * not allowed, since the argument is optional.
@@@ -2175,7 -2122,7 +2179,7 @@@ int setup_revisions(int argc, const cha
                 *      call init_pathspec() to set revs->prune_data here.
                 * }
                 */
 -              ALLOC_GROW(prune_data.path, prune_data.nr+1, prune_data.alloc);
 +              ALLOC_GROW(prune_data.path, prune_data.nr + 1, prune_data.alloc);
                prune_data.path[prune_data.nr++] = NULL;
                parse_pathspec(&revs->prune_data, 0, 0,
                               revs->prefix, prune_data.path);
@@@ -3028,7 -2975,7 +3032,7 @@@ static struct commit *get_revision_inte
        if (revs->max_count) {
                c = get_revision_1(revs);
                if (c) {
 -                      while (0 < revs->skip_count) {
 +                      while (revs->skip_count > 0) {
                                revs->skip_count--;
                                c = get_revision_1(revs);
                                if (!c)
        if (c)
                c->object.flags |= SHOWN;
  
 -      if (!revs->boundary) {
 +      if (!revs->boundary)
                return c;
 -      }
  
        if (!c) {
                /*
@@@ -3090,8 -3038,9 +3094,8 @@@ struct commit *get_revision(struct rev_
  
        if (revs->reverse) {
                reversed = NULL;
 -              while ((c = get_revision_internal(revs))) {
 +              while ((c = get_revision_internal(revs)))
                        commit_list_insert(c, &reversed);
 -              }
                revs->commits = reversed;
                revs->reverse = 0;
                revs->reverse_output_stage = 1;
diff --combined revision.h
index 88967d6a24df852453f93cb7bc466386347b0c45,9957f3c6e5b123480d2276e7de5206c3a5b697db..1eb94c1548c019a4d41cb42af805918afbc237bf
@@@ -5,7 -5,6 +5,7 @@@
  #include "grep.h"
  #include "notes.h"
  #include "commit.h"
 +#include "diff.h"
  
  #define SEEN          (1u<<0)
  #define UNINTERESTING   (1u<<1)
@@@ -61,9 -60,6 +61,9 @@@ struct rev_info 
        /* The end-points specified by the end user */
        struct rev_cmdline_info cmdline;
  
 +      /* excluding from --branches, --refs, etc. expansion */
 +      struct string_list *ref_excludes;
 +
        /* Basic information */
        const char *prefix;
        const char *def;
        unsigned long min_age;
        int min_parents;
        int max_parents;
+       int (*include_check)(struct commit *, void *);
+       void *include_check_data;
  
        /* diff info for patches and for paths limiting */
        struct diff_options diffopt;
        struct saved_parents *saved_parents_slab;
  };
  
 +extern int ref_excluded(struct string_list *, const char *path);
 +void clear_ref_exclusion(struct string_list **);
 +void add_ref_exclusion(struct string_list **, const char *exclude);
 +
 +
  #define REV_TREE_SAME         0
  #define REV_TREE_NEW          1       /* Only new files */
  #define REV_TREE_OLD          2       /* Only files removed */
diff --combined sha1_file.c
index 6e8c05d10825ee93d8248f749d4bef513d772be4,36d55c05f782e717c8d3a730878050fee390fe5a..019628add50f4957c21f32abb99c06fc6e5f5d2c
@@@ -105,63 -105,50 +105,63 @@@ int mkdir_in_gitdir(const char *path
        return adjust_shared_perm(path);
  }
  
 -int safe_create_leading_directories(char *path)
 +enum scld_error safe_create_leading_directories(char *path)
  {
 -      char *pos = path + offset_1st_component(path);
 -      struct stat st;
 +      char *next_component = path + offset_1st_component(path);
 +      enum scld_error ret = SCLD_OK;
 +
 +      while (ret == SCLD_OK && next_component) {
 +              struct stat st;
 +              char *slash = next_component, slash_character;
  
 -      while (pos) {
 -              pos = strchr(pos, '/');
 -              if (!pos)
 +              while (*slash && !is_dir_sep(*slash))
 +                      slash++;
 +
 +              if (!*slash)
                        break;
 -              while (*++pos == '/')
 -                      ;
 -              if (!*pos)
 +
 +              next_component = slash + 1;
 +              while (is_dir_sep(*next_component))
 +                      next_component++;
 +              if (!*next_component)
                        break;
 -              *--pos = '\0';
 +
 +              slash_character = *slash;
 +              *slash = '\0';
                if (!stat(path, &st)) {
                        /* path exists */
 -                      if (!S_ISDIR(st.st_mode)) {
 -                              *pos = '/';
 -                              return -3;
 -                      }
 -              }
 -              else if (mkdir(path, 0777)) {
 +                      if (!S_ISDIR(st.st_mode))
 +                              ret = SCLD_EXISTS;
 +              } else if (mkdir(path, 0777)) {
                        if (errno == EEXIST &&
 -                          !stat(path, &st) && S_ISDIR(st.st_mode)) {
 +                          !stat(path, &st) && S_ISDIR(st.st_mode))
                                ; /* somebody created it since we checked */
 -                      } else {
 -                              *pos = '/';
 -                              return -1;
 -                      }
 -              }
 -              else if (adjust_shared_perm(path)) {
 -                      *pos = '/';
 -                      return -2;
 +                      else if (errno == ENOENT)
 +                              /*
 +                               * Either mkdir() failed because
 +                               * somebody just pruned the containing
 +                               * directory, or stat() failed because
 +                               * the file that was in our way was
 +                               * just removed.  Either way, inform
 +                               * the caller that it might be worth
 +                               * trying again:
 +                               */
 +                              ret = SCLD_VANISHED;
 +                      else
 +                              ret = SCLD_FAILED;
 +              } else if (adjust_shared_perm(path)) {
 +                      ret = SCLD_PERMS;
                }
 -              *pos++ = '/';
 +              *slash = slash_character;
        }
 -      return 0;
 +      return ret;
  }
  
 -int safe_create_leading_directories_const(const char *path)
 +enum scld_error safe_create_leading_directories_const(const char *path)
  {
        /* path points to cache entries, so xstrdup before messing with it */
        char *buf = xstrdup(path);
 -      int result = safe_create_leading_directories(buf);
 +      enum scld_error result = safe_create_leading_directories(buf);
        free(buf);
        return result;
  }
@@@ -252,8 -239,6 +252,6 @@@ char *sha1_pack_index_name(const unsign
  struct alternate_object_database *alt_odb_list;
  static struct alternate_object_database **alt_odb_tail;
  
- static int git_open_noatime(const char *name);
  /*
   * Prepare alternate object database registry.
   *
@@@ -820,38 -805,15 +818,38 @@@ void free_pack_by_name(const char *pack
  static unsigned int get_max_fd_limit(void)
  {
  #ifdef RLIMIT_NOFILE
 -      struct rlimit lim;
 +      {
 +              struct rlimit lim;
  
 -      if (getrlimit(RLIMIT_NOFILE, &lim))
 -              die_errno("cannot get RLIMIT_NOFILE");
 +              if (!getrlimit(RLIMIT_NOFILE, &lim))
 +                      return lim.rlim_cur;
 +      }
 +#endif
 +
 +#ifdef _SC_OPEN_MAX
 +      {
 +              long open_max = sysconf(_SC_OPEN_MAX);
 +              if (0 < open_max)
 +                      return open_max;
 +              /*
 +               * Otherwise, we got -1 for one of the two
 +               * reasons:
 +               *
 +               * (1) sysconf() did not understand _SC_OPEN_MAX
 +               *     and signaled an error with -1; or
 +               * (2) sysconf() said there is no limit.
 +               *
 +               * We _could_ clear errno before calling sysconf() to
 +               * tell these two cases apart and return a huge number
 +               * in the latter case to let the caller cap it to a
 +               * value that is not so selfish, but letting the
 +               * fallback OPEN_MAX codepath take care of these cases
 +               * is a lot simpler.
 +               */
 +      }
 +#endif
  
 -      return lim.rlim_cur;
 -#elif defined(_SC_OPEN_MAX)
 -      return sysconf(_SC_OPEN_MAX);
 -#elif defined(OPEN_MAX)
 +#ifdef OPEN_MAX
        return OPEN_MAX;
  #else
        return 1; /* see the caller ;-) */
@@@ -1232,6 -1194,7 +1230,7 @@@ static void prepare_packed_git_one(cha
  
                if (has_extension(de->d_name, ".idx") ||
                    has_extension(de->d_name, ".pack") ||
+                   has_extension(de->d_name, ".bitmap") ||
                    has_extension(de->d_name, ".keep"))
                        string_list_append(&garbage, path);
                else
@@@ -1316,7 -1279,6 +1315,6 @@@ void prepare_packed_git(void
  
  void reprepare_packed_git(void)
  {
-       discard_revindex();
        prepare_packed_git_run_once = 0;
        prepare_packed_git();
  }
@@@ -1393,7 -1355,7 +1391,7 @@@ int check_sha1_signature(const unsigne
        return hashcmp(sha1, real_sha1) ? -1 : 0;
  }
  
static int git_open_noatime(const char *name)
+ int git_open_noatime(const char *name)
  {
        static int sha1_file_open_flag = O_NOATIME;
  
@@@ -1478,6 -1440,51 +1476,6 @@@ void *map_sha1_file(const unsigned cha
        return map;
  }
  
 -/*
 - * There used to be a second loose object header format which
 - * was meant to mimic the in-pack format, allowing for direct
 - * copy of the object data.  This format turned up not to be
 - * really worth it and we no longer write loose objects in that
 - * format.
 - */
 -static int experimental_loose_object(unsigned char *map)
 -{
 -      unsigned int word;
 -
 -      /*
 -       * We must determine if the buffer contains the standard
 -       * zlib-deflated stream or the experimental format based
 -       * on the in-pack object format. Compare the header byte
 -       * for each format:
 -       *
 -       * RFC1950 zlib w/ deflate : 0www1000 : 0 <= www <= 7
 -       * Experimental pack-based : Stttssss : ttt = 1,2,3,4
 -       *
 -       * If bit 7 is clear and bits 0-3 equal 8, the buffer MUST be
 -       * in standard loose-object format, UNLESS it is a Git-pack
 -       * format object *exactly* 8 bytes in size when inflated.
 -       *
 -       * However, RFC1950 also specifies that the 1st 16-bit word
 -       * must be divisible by 31 - this checksum tells us our buffer
 -       * is in the standard format, giving a false positive only if
 -       * the 1st word of the Git-pack format object happens to be
 -       * divisible by 31, ie:
 -       *      ((byte0 * 256) + byte1) % 31 = 0
 -       *   =>        0ttt10000www1000 % 31 = 0
 -       *
 -       * As it happens, this case can only arise for www=3 & ttt=1
 -       * - ie, a Commit object, which would have to be 8 bytes in
 -       * size. As no Commit can be that small, we find that the
 -       * combination of these two criteria (bitmask & checksum)
 -       * can always correctly determine the buffer format.
 -       */
 -      word = (map[0] << 8) + map[1];
 -      if ((map[0] & 0x8F) == 0x08 && !(word % 31))
 -              return 0;
 -      else
 -              return 1;
 -}
 -
  unsigned long unpack_object_header_buffer(const unsigned char *buf,
                unsigned long len, enum object_type *type, unsigned long *sizep)
  {
  
  int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
  {
 -      unsigned long size, used;
 -      static const char valid_loose_object_type[8] = {
 -              0, /* OBJ_EXT */
 -              1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
 -              0, /* "delta" and others are invalid in a loose object */
 -      };
 -      enum object_type type;
 -
        /* Get the data stream */
        memset(stream, 0, sizeof(*stream));
        stream->next_in = map;
        stream->next_out = buffer;
        stream->avail_out = bufsiz;
  
 -      if (experimental_loose_object(map)) {
 -              /*
 -               * The old experimental format we no longer produce;
 -               * we can still read it.
 -               */
 -              used = unpack_object_header_buffer(map, mapsize, &type, &size);
 -              if (!used || !valid_loose_object_type[type])
 -                      return -1;
 -              map += used;
 -              mapsize -= used;
 -
 -              /* Set up the stream for the rest.. */
 -              stream->next_in = map;
 -              stream->avail_in = mapsize;
 -              git_inflate_init(stream);
 -
 -              /* And generate the fake traditional header */
 -              stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
 -                                               typename(type), size);
 -              return 0;
 -      }
        git_inflate_init(stream);
        return git_inflate(stream, 0);
  }
@@@ -1703,38 -1739,6 +1701,38 @@@ static off_t get_delta_base(struct pack
        return base_offset;
  }
  
 +/*
 + * Like get_delta_base above, but we return the sha1 instead of the pack
 + * offset. This means it is cheaper for REF deltas (we do not have to do
 + * the final object lookup), but more expensive for OFS deltas (we
 + * have to load the revidx to convert the offset back into a sha1).
 + */
 +static const unsigned char *get_delta_base_sha1(struct packed_git *p,
 +                                              struct pack_window **w_curs,
 +                                              off_t curpos,
 +                                              enum object_type type,
 +                                              off_t delta_obj_offset)
 +{
 +      if (type == OBJ_REF_DELTA) {
 +              unsigned char *base = use_pack(p, w_curs, curpos, NULL);
 +              return base;
 +      } else if (type == OBJ_OFS_DELTA) {
 +              struct revindex_entry *revidx;
 +              off_t base_offset = get_delta_base(p, w_curs, &curpos,
 +                                                 type, delta_obj_offset);
 +
 +              if (!base_offset)
 +                      return NULL;
 +
 +              revidx = find_pack_revindex(p, base_offset);
 +              if (!revidx)
 +                      return NULL;
 +
 +              return nth_packed_object_sha1(p, revidx->nr);
 +      } else
 +              return NULL;
 +}
 +
  int unpack_object_header(struct packed_git *p,
                         struct pack_window **w_curs,
                         off_t *curpos,
@@@ -1892,22 -1896,6 +1890,22 @@@ static int packed_object_info(struct pa
                }
        }
  
 +      if (oi->delta_base_sha1) {
 +              if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
 +                      const unsigned char *base;
 +
 +                      base = get_delta_base_sha1(p, &w_curs, curpos,
 +                                                 type, obj_offset);
 +                      if (!base) {
 +                              type = OBJ_BAD;
 +                              goto out;
 +                      }
 +
 +                      hashcpy(oi->delta_base_sha1, base);
 +              } else
 +                      hashclr(oi->delta_base_sha1);
 +      }
 +
  out:
        unuse_pack(&w_curs);
        return type;
@@@ -2491,23 -2479,17 +2489,23 @@@ static int sha1_loose_object_info(cons
        git_zstream stream;
        char hdr[32];
  
 +      if (oi->delta_base_sha1)
 +              hashclr(oi->delta_base_sha1);
 +
        /*
         * If we don't care about type or size, then we don't
 -       * need to look inside the object at all.
 +       * need to look inside the object at all. Note that we
 +       * do not optimize out the stat call, even if the
 +       * caller doesn't care about the disk-size, since our
 +       * return value implicitly indicates whether the
 +       * object even exists.
         */
        if (!oi->typep && !oi->sizep) {
 -              if (oi->disk_sizep) {
 -                      struct stat st;
 -                      if (stat_sha1_file(sha1, &st) < 0)
 -                              return -1;
 +              struct stat st;
 +              if (stat_sha1_file(sha1, &st) < 0)
 +                      return -1;
 +              if (oi->disk_sizep)
                        *oi->disk_sizep = st.st_size;
 -              }
                return 0;
        }
  
        return 0;
  }
  
 -/* returns enum object_type or negative */
 -int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
 +int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
  {
        struct cached_object *co;
        struct pack_entry e;
        int rtype;
 +      const unsigned char *real = lookup_replace_object_extended(sha1, flags);
  
 -      co = find_cached_object(sha1);
 +      co = find_cached_object(real);
        if (co) {
                if (oi->typep)
                        *(oi->typep) = co->type;
                        *(oi->sizep) = co->size;
                if (oi->disk_sizep)
                        *(oi->disk_sizep) = 0;
 +              if (oi->delta_base_sha1)
 +                      hashclr(oi->delta_base_sha1);
                oi->whence = OI_CACHED;
                return 0;
        }
  
 -      if (!find_pack_entry(sha1, &e)) {
 +      if (!find_pack_entry(real, &e)) {
                /* Most likely it's a loose object. */
 -              if (!sha1_loose_object_info(sha1, oi)) {
 +              if (!sha1_loose_object_info(real, oi)) {
                        oi->whence = OI_LOOSE;
                        return 0;
                }
  
                /* Not a loose object; someone else may have just packed it. */
                reprepare_packed_git();
 -              if (!find_pack_entry(sha1, &e))
 +              if (!find_pack_entry(real, &e))
                        return -1;
        }
  
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
 -              mark_bad_packed_object(e.p, sha1);
 -              return sha1_object_info_extended(sha1, oi);
 +              mark_bad_packed_object(e.p, real);
 +              return sha1_object_info_extended(real, oi, 0);
        } else if (in_delta_base_cache(e.p, e.offset)) {
                oi->whence = OI_DBCACHED;
        } else {
        return 0;
  }
  
 +/* returns enum object_type or negative */
  int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
  {
        enum object_type type;
  
        oi.typep = &type;
        oi.sizep = sizep;
 -      if (sha1_object_info_extended(sha1, &oi) < 0)
 +      if (sha1_object_info_extended(sha1, &oi, LOOKUP_REPLACE_OBJECT) < 0)
                return -1;
        return type;
  }
@@@ -2681,7 -2660,8 +2679,7 @@@ void *read_sha1_file_extended(const uns
        void *data;
        char *path;
        const struct packed_git *p;
 -      const unsigned char *repl = (flag & READ_SHA1_FILE_REPLACE)
 -              ? lookup_replace_object(sha1) : sha1;
 +      const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
  
        errno = 0;
        data = read_object(repl, type, size);
@@@ -2875,9 -2855,7 +2873,9 @@@ static int create_tmpfile(char *buffer
                /* Make sure the directory exists */
                memcpy(buffer, filename, dirlen);
                buffer[dirlen-1] = 0;
 -              if (mkdir(buffer, 0777) || adjust_shared_perm(buffer))
 +              if (mkdir(buffer, 0777) && errno != EEXIST)
 +                      return -1;
 +              if (adjust_shared_perm(buffer))
                        return -1;
  
                /* Try again */