Merge branch 'bc/hash-independent-tests'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 12:51:28 +0000 (21:51 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 12:51:28 +0000 (21:51 +0900)
Many tests hardcode the raw object names, which would change once
we migrate away from SHA-1.  While some of them must test against
exact object names, most of them do not have to use hardcoded
constants in the test.  The latter kind of tests have been updated
to test the moral equivalent of the original without hardcoding the
actual object names.

* bc/hash-independent-tests: (28 commits)
  t5300: abstract away SHA-1-specific constants
  t4208: abstract away SHA-1-specific constants
  t4045: abstract away SHA-1-specific constants
  t4042: abstract away SHA-1-specific constants
  t4205: sort log output in a hash-independent way
  t/lib-diff-alternative: abstract away SHA-1-specific constants
  t4030: abstract away SHA-1-specific constants
  t4029: abstract away SHA-1-specific constants
  t4029: fix test indentation
  t4022: abstract away SHA-1-specific constants
  t4020: abstract away SHA-1-specific constants
  t4014: abstract away SHA-1-specific constants
  t4008: abstract away SHA-1-specific constants
  t4007: abstract away SHA-1-specific constants
  t3905: abstract away SHA-1-specific constants
  t3702: abstract away SHA-1-specific constants
  t3103: abstract away SHA-1-specific constants
  t2203: abstract away SHA-1-specific constants
  t: skip pack tests if not using SHA-1
  t4044: skip test if not using SHA-1
  ...

329 files changed:
.gitattributes
.mailmap
.travis.yml
Documentation/Makefile
Documentation/RelNotes/2.13.7.txt [new file with mode: 0644]
Documentation/RelNotes/2.14.4.txt [new file with mode: 0644]
Documentation/RelNotes/2.15.2.txt
Documentation/RelNotes/2.16.4.txt [new file with mode: 0644]
Documentation/RelNotes/2.17.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.18.0.txt
Documentation/config.txt
Documentation/diff-config.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-apply.txt
Documentation/git-branch.txt
Documentation/git-bundle.txt
Documentation/git-clone.txt
Documentation/git-cvsserver.txt
Documentation/git-diff-index.txt
Documentation/git-diff-tree.txt
Documentation/git-diff.txt
Documentation/git-fast-export.txt
Documentation/git-fast-import.txt
Documentation/git-filter-branch.txt
Documentation/git-fmt-merge-msg.txt
Documentation/git-gc.txt
Documentation/git-grep.txt
Documentation/git-http-push.txt
Documentation/git-imap-send.txt
Documentation/git-index-pack.txt
Documentation/git-ls-files.txt
Documentation/git-ls-remote.txt
Documentation/git-name-rev.txt
Documentation/git-p4.txt
Documentation/git-pack-objects.txt
Documentation/git-prune.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-read-tree.txt
Documentation/git-rebase.txt
Documentation/git-receive-pack.txt
Documentation/git-remote-ext.txt
Documentation/git-remote.txt
Documentation/git-repack.txt
Documentation/git-replace.txt
Documentation/git-request-pull.txt
Documentation/git-send-email.txt
Documentation/git-send-pack.txt
Documentation/git-shell.txt
Documentation/git-show-branch.txt
Documentation/git-show-ref.txt
Documentation/git-show.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git-update-index.txt
Documentation/git-update-ref.txt
Documentation/git-var.txt
Documentation/git-web--browse.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/githooks.txt
Documentation/merge-config.txt
Documentation/merge-strategies.txt
Documentation/revisions.txt
Documentation/technical/api-config.txt
Documentation/technical/api-oid-array.txt
Documentation/technical/pack-format.txt
Documentation/technical/protocol-v2.txt
Documentation/technical/shallow.txt
Makefile
advice.c
advice.h
apply.c
archive-tar.c
archive-zip.c
argv-array.c
argv-array.h
attr.c
blame.c
branch.c
builtin/add.c
builtin/am.c
builtin/blame.c
builtin/branch.c
builtin/cat-file.c
builtin/checkout.c
builtin/clone.c
builtin/column.c
builtin/commit.c
builtin/config.c
builtin/count-objects.c
builtin/describe.c
builtin/diff.c
builtin/difftool.c
builtin/fast-export.c
builtin/fetch.c
builtin/fsck.c
builtin/gc.c
builtin/grep.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-remote.c
builtin/ls-tree.c
builtin/merge.c
builtin/mktree.c
builtin/mv.c
builtin/notes.c
builtin/pack-objects.c
builtin/pack-redundant.c
builtin/prune-packed.c
builtin/prune.c
builtin/pull.c
builtin/push.c
builtin/read-tree.c
builtin/rebase--helper.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/reset.c
builtin/rev-parse.c
builtin/rm.c
builtin/send-pack.c
builtin/submodule--helper.c
builtin/tag.c
builtin/unpack-objects.c
builtin/update-index.c
builtin/worktree.c
bulk-checkin.c
bundle.c
cache-tree.c
cache.h
checkout.c
ci/lib-travisci.sh
ci/run-build-and-tests.sh
color.c
column.c
commit-graph.c
commit-graph.h
commit.c
commit.h
config.c
config.mak.uname
connect.c
contrib/coccinelle/commit.cocci [new file with mode: 0644]
contrib/completion/git-completion.bash
contrib/completion/git-completion.zsh
contrib/convert-grafts-to-replace-refs.sh [deleted file]
contrib/credential/netrc/Makefile
contrib/credential/netrc/git-credential-netrc
contrib/credential/netrc/t-git-credential-netrc.sh [new file with mode: 0755]
contrib/credential/netrc/test.command-option-gpg [new file with mode: 0755]
contrib/credential/netrc/test.git-config-gpg [new file with mode: 0755]
contrib/credential/netrc/test.netrc.gpg [new file with mode: 0644]
contrib/credential/netrc/test.pl
date.c
diff.c
diff.h
diffcore-pickaxe.c
dir-iterator.c
dir.c
dir.h
fast-import.c
fetch-pack.c
fetch-pack.h
fsck.c
fsck.h
fsmonitor.c
git-add--interactive.perl
git-compat-util.h
git-filter-branch.sh
git-merge-one-file.sh
git-p4.py
git-rebase--interactive.sh
git-rebase.sh
git-send-email.perl
git-submodule.sh
git.c
grep.c
http-push.c
http.c
http.h
imap-send.c
line-log.c
list-objects-filter.c
list-objects.c
lockfile.c
log-tree.c
log-tree.h
mailinfo.c
merge-recursive.c
merge-recursive.h
merge.c
notes-merge.c
object-store.h
object.c
object.h
pack-bitmap-write.c
pack-bitmap.c
pack-bitmap.h
pack-check.c
pack-objects.c
pack-objects.h
packfile.c
packfile.h
pager.c
path.c
pathspec.c
pkt-line.c
pretty.c
prio-queue.c
reachable.c
read-cache.c
ref-filter.c
refs.c
refs/files-backend.c
refs/iterator.c
refs/packed-backend.c
refs/ref-cache.c
refspec.c [new file with mode: 0644]
refspec.h [new file with mode: 0644]
remote.c
remote.h
replace-object.c
repository.c
rerere.c
resolve-undo.c
revision.c
run-command.c
sequencer.c
sequencer.h
serve.c
server-info.c
setup.c
sha1-array.c
sha1-array.h
sha1-file.c
sha1-lookup.c
sha1-name.c
shallow.c
sigchain.c
split-index.c
split-index.h
strbuf.c
strbuf.h
streaming.c
submodule-config.c
submodule-config.h
submodule.c
submodule.h
t/README
t/helper/test-drop-caches.c
t/helper/test-dump-split-index.c
t/helper/test-dump-untracked-cache.c
t/helper/test-example-decorate.c
t/helper/test-path-utils.c
t/helper/test-scrap-cache-tree.c
t/helper/test-tool.c
t/helper/test-write-cache.c
t/lib-pack.sh
t/perf/aggregate.perl
t/perf/bisect_run_script
t/t0060-path-utils.sh
t/t1307-config-blob.sh
t/t1400-update-ref.sh
t/t1512-rev-parse-disambiguation.sh
t/t2025-worktree-add.sh
t/t3034-merge-recursive-rename-options.sh
t/t3404-rebase-interactive.sh
t/t3418-rebase-continue.sh
t/t3421-rebase-topology-linear.sh
t/t3430-rebase-merges.sh [new file with mode: 0755]
t/t3501-revert-cherry-pick.sh
t/t4001-diff-rename.sh
t/t4014-format-patch.sh
t/t5300-pack-object.sh
t/t5310-pack-bitmaps.sh
t/t5512-ls-remote.sh
t/t5516-fetch-push.sh
t/t5701-git-serve.sh
t/t5702-protocol-v2.sh
t/t6001-rev-list-graft.sh
t/t6022-merge-rename.sh
t/t6043-merge-rename-directories.sh [new file with mode: 0755]
t/t6046-merge-skip-unneeded-updates.sh [new file with mode: 0755]
t/t6050-replace.sh
t/t6500-gc.sh
t/t7004-tag.sh
t/t7005-editor.sh
t/t7400-submodule-basic.sh
t/t7408-submodule-reference.sh
t/t7415-submodule-names.sh [new file with mode: 0755]
t/t7525-status-rename.sh [new file with mode: 0755]
t/t7607-merge-overwrite.sh
t/t7700-repack.sh
t/t8012-blame-colors.sh [new file with mode: 0755]
t/t9902-completion.sh
t/test-lib-functions.sh
t/test-lib.sh
tag.c
templates/hooks--pre-commit.sample
tmp-objdir.c
trailer.c
transport-helper.c
transport.c
transport.h
tree-walk.c
tree-walk.h
tree.c
unpack-trees.c
unpack-trees.h
upload-pack.c
usage.c
utf8.c
utf8.h
vcs-svn/fast_export.c
walker.c
worktree.c
wrap-for-bin.sh
wrapper.c
wt-status.c
wt-status.h
zlib.c

index 8ce9c6b..1bdc91e 100644 (file)
@@ -1,8 +1,10 @@
 * whitespace=!indent,trail,space
 *.[ch] whitespace=indent,trail,space diff=cpp
 *.sh whitespace=indent,trail,space eol=lf
-*.perl eol=lf
-*.pm eol=lf
+*.perl eol=lf diff=perl
+*.pl eof=lf diff=perl
+*.pm eol=lf diff=perl
+*.py eol=lf diff=python
 /Documentation/git-*.txt eol=lf
 /command-list.txt eol=lf
 /GIT-VERSION-GEN eol=lf
index 7c71e88..df7cf63 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -25,8 +25,8 @@ Ben Walton <bdwalton@gmail.com> <bwalton@artsci.utoronto.ca>
 Benoit Sigoure <tsunanet@gmail.com> <tsuna@lrde.epita.fr>
 Bernt Hansen <bernt@norang.ca> <bernt@alumni.uwaterloo.ca>
 Brandon Casey <drafnel@gmail.com> <casey@nrlssc.navy.mil>
-brian m. carlson <sandals@crustytoothpaste.ath.cx> Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
-brian m. carlson <sandals@crustytoothpaste.ath.cx> <sandals@crustytoothpaste.net>
+brian m. carlson <sandals@crustytoothpaste.net> Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
+brian m. carlson <sandals@crustytoothpaste.net> <sandals@crustytoothpaste.ath.cx>
 Bryan Larsen <bryan@larsen.st> <bryan.larsen@gmail.com>
 Bryan Larsen <bryan@larsen.st> <bryanlarsen@yahoo.com>
 Cheng Renquan <crquan@gmail.com>
index 5f5ee4f..4d4e26c 100644 (file)
@@ -16,10 +16,13 @@ compiler:
 
 addons:
   apt:
+    sources:
+    - ubuntu-toolchain-r-test
     packages:
     - language-pack-is
     - git-svn
     - apache2
+    - gcc-8
 
 matrix:
   include:
index fa9e5c0..d079d7c 100644 (file)
@@ -185,7 +185,7 @@ ASCIIDOC = asciidoctor
 ASCIIDOC_CONF =
 ASCIIDOC_HTML = xhtml5
 ASCIIDOC_DOCBOOK = docbook45
-ASCIIDOC_EXTRA += -acompat-mode
+ASCIIDOC_EXTRA += -acompat-mode -atabsize=8
 ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
 ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;'
 DBLATEX_COMMON =
diff --git a/Documentation/RelNotes/2.13.7.txt b/Documentation/RelNotes/2.13.7.txt
new file mode 100644 (file)
index 0000000..09fc014
--- /dev/null
@@ -0,0 +1,20 @@
+Git v2.13.7 Release Notes
+=========================
+
+Fixes since v2.13.6
+-------------------
+
+ * Submodule "names" come from the untrusted .gitmodules file, but we
+   blindly append them to $GIT_DIR/modules to create our on-disk repo
+   paths. This means you can do bad things by putting "../" into the
+   name. We now enforce some rules for submodule names which will cause
+   Git to ignore these malicious names (CVE-2018-11235).
+
+   Credit for finding this vulnerability and the proof of concept from
+   which the test script was adapted goes to Etienne Stalmans.
+
+ * It was possible to trick the code that sanity-checks paths on NTFS
+   into reading random piece of memory (CVE-2018-11233).
+
+Credit for fixing for these bugs goes to Jeff King, Johannes
+Schindelin and others.
diff --git a/Documentation/RelNotes/2.14.4.txt b/Documentation/RelNotes/2.14.4.txt
new file mode 100644 (file)
index 0000000..97755a8
--- /dev/null
@@ -0,0 +1,5 @@
+Git v2.14.4 Release Notes
+=========================
+
+This release is to forward-port the fixes made in the v2.13.7 version
+of Git.  See its release notes for details.
index 9f7e28f..b480e56 100644 (file)
@@ -43,5 +43,8 @@ Fixes since v2.15.1
  * Clarify and enhance documentation for "merge-base --fork-point", as
    it was clear what it computed but not why/what for.
 
+ * This release also contains the fixes made in the v2.13.7 version of
+   Git.  See its release notes for details.
+
 
 Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.16.4.txt b/Documentation/RelNotes/2.16.4.txt
new file mode 100644 (file)
index 0000000..6be538b
--- /dev/null
@@ -0,0 +1,5 @@
+Git v2.16.4 Release Notes
+=========================
+
+This release is to forward-port the fixes made in the v2.13.7 version
+of Git.  See its release notes for details.
diff --git a/Documentation/RelNotes/2.17.1.txt b/Documentation/RelNotes/2.17.1.txt
new file mode 100644 (file)
index 0000000..e01384f
--- /dev/null
@@ -0,0 +1,16 @@
+Git v2.17.1 Release Notes
+=========================
+
+Fixes since v2.17
+-----------------
+
+ * This release contains the same fixes made in the v2.13.7 version of
+   Git, covering CVE-2018-11233 and 11235, and forward-ported to
+   v2.14.4, v2.15.2 and v2.16.4 releases.  See release notes to
+   v2.13.7 for details.
+
+ * In addition to the above fixes, this release has support on the
+   server side to reject pushes to repositories that attempt to create
+   such problematic .gitmodules file etc. as tracked contents, to help
+   hosting sites protect their customers by preventing malicious
+   contents from spreading.
index fccc2f3..d750d01 100644 (file)
@@ -82,6 +82,57 @@ UI, Workflows & Features
    "feature" to fetch only commits and/or trees, which nobody used.
    This has been removed.
 
+ * The functionality of "$GIT_DIR/info/grafts" has been superseded by
+   the "refs/replace/" mechanism for some time now, but the internal
+   code had support for it in many places, which has been cleaned up
+   in order to drop support of the "grafts" mechanism.
+
+ * "git worktree add" learned to check out an existing branch.
+
+ * "git --no-pager cmd" did not have short-and-sweet single letter
+   option. Now it does as "-P".
+   (merge 7213c28818 js/no-pager-shorthand later to maint).
+
+ * "git rebase" learned "--rebase-merges" to transplant the whole
+   topology of commit graph elsewhere.
+
+ * "git status" learned to pay attention to UI related diff
+   configuration variables such as diff.renames.
+
+ * The command line completion mechanism (in contrib/) learned to load
+   custom completion file for "git $command" where $command is a
+   custom "git-$command" that the end user has on the $PATH when using
+   newer version of bash.
+
+ * "git send-email" can sometimes offer confirmation dialog "Send this
+   email?" with choices 'Yes', 'No', 'Quit', and 'All'.  A new action
+   'Edit' has been added to this dialog's choice.
+
+ * With merge.renames configuration set to false, the recursive merge
+   strategy can be told not to spend cycles trying to find renamed
+   paths and merge them accordingly.
+
+ * "git status" learned to honor a new status.renames configuration to
+   skip rename detection, which could be useful for those who want to
+   do so without disabling the default rename detection done by the
+   "git diff" command.
+
+ * Command line completion (in contrib/) learned to complete pathnames
+   for various commands better.
+
+ * "git blame" learns to unhighlight uninteresting metadata from the
+   originating commit on lines that are the same as the previous one,
+   and also paint lines in different colors depending on the age of
+   the commit.
+
+ * Transfer protocol v2 learned to support the partial clone.
+
+ * When a short hexadecimal string is used to name an object but there
+   are multiple objects that share the string as the prefix of their
+   names, the code lists these ambiguous candidates in a help message.
+   These object names are now sorted according to their types for
+   easier eyeballing.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -179,6 +230,48 @@ Performance, Internal Implementation, Development Support etc.
  * The code to interface to GPG has been restructured somewhat to make
    it cleaner to integrate with other types of signature systems later.
 
+ * The code has been taught to use the duplicated information stored
+   in the commit-graph file to learn the tree object name for a commit
+   to avoid opening and parsing the commit object when it makes sense
+   to do so.
+
+ * "git gc" in a large repository takes a lot of time as it considers
+   to repack all objects into one pack by default.  The command has
+   been taught to pretend as if the largest existing packfile is
+   marked with ".keep" so that it is left untouched while objects in
+   other packs and loose ones are repacked.
+
+ * The transport protocol v2 is getting updated further.
+
+ * The codepath around object-info API has been taught to take the
+   repository object (which in turn tells the API which object store
+   the objects are to be located).
+
+ * Rename detection logic in "diff" family that is used in "merge" has
+   learned to guess when all of x/a, x/b and x/c have moved to z/a,
+   z/b and z/c, it is likely that x/d added in the meantime would also
+   want to move to z/d by taking the hint that the entire directory
+   'x' moved to 'z'.  A bug causing dirty files involved in a rename
+   to be overwritten during merge has also been fixed as part of this
+   work.  Incidentally, this also avoids updating a file in the
+   working tree after a (non-trivial) merge whose result matches what
+   our side originally had.
+
+ * "git pack-objects" needs to allocate tons of "struct object_entry"
+   while doing its work, and shrinking its size helps the performance
+   quite a bit.
+
+ * The implementation of "git rebase -i --root" has been updated to use
+   the sequencer machinery more.
+
+ * Developer support update, by using BUG() macro instead of die() to
+   mark codepaths that should not happen more clearly.
+
+ * Developer support.  Use newer GCC on one of the builds done at
+   TravisCI.org to get more warnings and errors diagnosed.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
 
 Also contains various documentation updates and code clean-ups.
 
@@ -292,6 +385,82 @@ Fixes since v2.17
    some merge commits in certain cases, which has been corrected.
    (merge be011bbe00 ma/fast-export-skip-merge-fix later to maint).
 
+ * The code did not propagate the terminal width to subprocesses via
+   COLUMNS environment variable, which it now does.  This caused
+   trouble to "git column" helper subprocess when "git tag --column=row"
+   tried to list the existing tags on a display with non-default width.
+   (merge b5d5a567fb nd/term-columns later to maint).
+
+ * We learned that our source files with ".pl" and ".py" extensions
+   are Perl and Python files respectively and changes to them are
+   better viewed as such with appropriate diff drivers.
+   (merge 7818b619e2 ab/perl-python-attrs later to maint).
+
+ * "git rebase -i" sometimes left intermediate "# This is a
+   combination of N commits" message meant for the human consumption
+   inside an editor in the final result in certain corner cases, which
+   has been fixed.
+   (merge 15ef69314d js/rebase-i-clean-msg-after-fixup-continue later to maint).
+
+ * A test to see if the filesystem normalizes UTF-8 filename has been
+   updated to check what we need to know in a more direct way, i.e. a
+   path created in NFC form can be accessed with NFD form (or vice
+   versa) to cope with APFS as well as HFS.
+   (merge 742ae10e35 tb/test-apfs-utf8-normalization later to maint).
+
+ * "git format-patch --cover --attach" created a broken MIME multipart
+   message for the cover letter, which has been fixed by keeping the
+   cover letter as plain text file.
+   (merge 50cd54ef4e bc/format-patch-cover-no-attach later to maint).
+
+ * The split-index feature had a long-standing and dormant bug in
+   certain use of the in-core merge machinery, which has been fixed.
+   (merge 7db118303a en/unpack-trees-split-index-fix later to maint).
+
+ * Asciidoctor gives a reasonable imitation for AsciiDoc, but does not
+   render illustration in a literal block correctly when indented with
+   HT by default. The problem is fixed by forcing 8-space tabs.
+   (merge 379805051d bc/asciidoctor-tab-width later to maint).
+
+ * Code clean-up to adjust to a more recent lockfile API convention that
+   allows lockfile instances kept on the stack.
+   (merge 0fa5a2ed8d ma/lockfile-cleanup later to maint).
+
+ * the_repository->index is not a allocated piece of memory but
+   repo_clear() indiscriminately attempted to free(3) it, which has
+   been corrected.
+   (merge 74373b5f10 nd/repo-clear-keep-the-index later to maint).
+
+ * Code clean-up to avoid non-standard-conformant pointer arithmetic.
+   (merge c112084af9 rs/no-null-ptr-arith-in-fast-export later to maint).
+
+ * Code clean-up to turn history traversal more robust in a
+   semi-corrupt repository.
+   (merge 8702b30fd7 jk/unavailable-can-be-missing later to maint).
+
+ * "git update-ref A B" is supposed to ensure that ref A does not yet
+   exist when B is a NULL OID, but this check was not done correctly
+   for pseudo-refs outside refs/ hierarchy, e.g. MERGE_HEAD.
+
+ * "git submodule update" and "git submodule add" supported the
+   "--reference" option to borrow objects from a neighbouring local
+   repository like "git clone" does, but lacked the more recent
+   invention "--dissociate".  Also "git submodule add" has been taught
+   to take the "--progress" option.
+   (merge a0ef29341a cf/submodule-progress-dissociate later to maint).
+
+ * Update credential-netrc helper (in contrib/) to allow customizing
+   the GPG used to decrypt the encrypted .netrc file.
+   (merge 786ef50a23 lm/credential-netrc later to maint).
+
+ * "git submodule update" attempts two different kinds of "git fetch"
+   against the upstream repository to grab a commit bound at the
+   submodule's path, but it incorrectly gave up if the first kind
+   (i.e. a normal fetch) failed, making the second "last resort" one
+   (i.e. fetching an exact commit object by object name) ineffective.
+   This has been corrected.
+   (merge e30d833671 sb/submodule-update-try-harder later to maint).
+
  * Other minor doc, test and build updates and code cleanups.
    (merge 248f66ed8e nd/trace-with-env later to maint).
    (merge 14ced5562c ys/bisect-object-id-missing-conversion-fix later to maint).
@@ -310,3 +479,15 @@ Fixes since v2.17
    (merge adc887221f tq/t1510 later to maint).
    (merge bed21a8ad6 sg/doc-gc-quote-mismatch-fix later to maint).
    (merge 73364e4f10 tz/doc-git-urls-reference later to maint).
+   (merge cd1e606bad bc/mailmap-self later to maint).
+   (merge f7997e3682 ao/config-api-doc later to maint).
+   (merge ee930754d8 jk/apply-p-doc later to maint).
+   (merge 011b648646 nd/pack-format-doc later to maint).
+   (merge 87a6bb701a sg/t5310-jgit-bitmap-test later to maint).
+   (merge f6b82970aa sg/t5516-fixes later to maint).
+   (merge 4362da078e sg/t7005-spaces-in-filenames-cleanup later to maint).
+   (merge 7d0ee47c11 js/test-unset-prereq later to maint).
+   (merge 5356a3c354 ah/misc-doc-updates later to maint).
+   (merge 92c4a7a129 nd/completion-aliasfiletype-typofix later to maint).
+   (merge 58bd77b66a nd/pack-unreachable-objects-doc later to maint).
+   (merge 4ed79d5203 sg/t6500-no-redirect-of-stdin later to maint).
index a05a88f..7d83834 100644 (file)
@@ -1068,6 +1068,10 @@ branch.<name>.rebase::
        "git pull" is run. See "pull.rebase" for doing this in a non
        branch-specific manner.
 +
+When `merges`, pass the `--rebase-merges` option to 'git rebase'
+so that the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
 When preserve, also pass `--preserve-merges` along to 'git rebase'
 so that locally committed merge commits will not be flattened
 by running 'git pull'.
@@ -1247,6 +1251,33 @@ color.status.<slot>::
        status short-format), or
        `unmerged` (files which have unmerged changes).
 
+color.blame.repeatedLines::
+       Use the customized color for the part of git-blame output that
+       is repeated meta information per line (such as commit id,
+       author name, date and timezone). Defaults to cyan.
+
+color.blame.highlightRecent::
+       This can be used to color the metadata of a blame line depending
+       on age of the line.
++
+This setting should be set to a comma-separated list of color and date settings,
+starting and ending with a color, the dates should be set from oldest to newest.
+The metadata will be colored given the colors if the the line was introduced
+before the given timestamp, overwriting older timestamped colors.
++
+Instead of an absolute timestamp relative timestamps work as well, e.g.
+2.weeks.ago is valid to address anything older than 2 weeks.
++
+It defaults to 'blue,12 month ago,white,1 month ago,red', which colors
+everything older than one year blue, recent changes between one month and
+one year old are kept white, and lines introduced within the last month are
+colored red.
+
+blame.coloring::
+       This determines the coloring scheme to be applied to blame
+       output. It can be 'repeatedLines', 'highlightRecent',
+       or 'none' which is the default.
+
 color.transport::
        A boolean to enable/disable color when pushes are rejected. May be
        set to `always`, `false` (or `never`) or `auto` (or `true`), in which
@@ -1596,6 +1627,18 @@ gc.autoDetach::
        Make `git gc --auto` return immediately and run in background
        if the system supports it. Default is true.
 
+gc.bigPackThreshold::
+       If non-zero, all packs larger than this limit are kept when
+       `git gc` is run. This is very similar to `--keep-base-pack`
+       except that all packs that meet the threshold are kept, not
+       just the base pack. Defaults to zero. Common unit suffixes of
+       'k', 'm', or 'g' are supported.
++
+Note that if the number of kept packs is more than gc.autoPackLimit,
+this configuration variable is ignored, all packs except the base pack
+will be repacked. After this the number of packs should go below
+gc.autoPackLimit and gc.bigPackThreshold should be respected again.
+
 gc.logExpiry::
        If the file gc.log exists, then `git gc --auto` won't run
        unless that file is more than 'gc.logExpiry' old.  Default is
@@ -2460,6 +2503,7 @@ pack.window::
 pack.depth::
        The maximum delta depth used by linkgit:git-pack-objects[1] when no
        maximum depth is given on the command line. Defaults to 50.
+       Maximum value is 4095.
 
 pack.windowMemory::
        The maximum size of memory that is consumed by each thread
@@ -2496,7 +2540,8 @@ pack.deltaCacheLimit::
        The maximum size of a delta, that is cached in
        linkgit:git-pack-objects[1]. This cache is used to speed up the
        writing object phase by not having to recompute the final delta
-       result once the best match for all objects is found. Defaults to 1000.
+       result once the best match for all objects is found.
+       Defaults to 1000. Maximum value is 65535.
 
 pack.threads::
        Specifies the number of threads to spawn when searching for best
@@ -2655,6 +2700,10 @@ pull.rebase::
        pull" is run. See "branch.<name>.rebase" for setting this on a
        per-branch basis.
 +
+When `merges`, pass the `--rebase-merges` option to 'git rebase'
+so that the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
 When preserve, also pass `--preserve-merges` along to 'git rebase'
 so that locally committed merge commits will not be flattened
 by running 'git pull'.
@@ -3157,6 +3206,18 @@ status.displayCommentPrefix::
        behavior of linkgit:git-status[1] in Git 1.8.4 and previous.
        Defaults to false.
 
+status.renameLimit::
+       The number of files to consider when performing rename detection
+       in linkgit:git-status[1] and linkgit:git-commit[1]. Defaults to
+       the value of diff.renameLimit.
+
+status.renames::
+       Whether and how Git detects renames in linkgit:git-status[1] and
+       linkgit:git-commit[1] .  If set to "false", rename detection is
+       disabled. If set to "true", basic rename detection is enabled.
+       If set to "copies" or "copy", Git will detect copies, as well.
+       Defaults to the value of diff.renames.
+
 status.showStash::
        If set to true, linkgit:git-status[1] will display the number of
        entries currently stashed away.
index 5ca942a..77caa66 100644 (file)
@@ -112,7 +112,8 @@ diff.orderFile::
 
 diff.renameLimit::
        The number of files to consider when performing the copy/rename
-       detection; equivalent to the 'git diff' option `-l`.
+       detection; equivalent to the 'git diff' option `-l`. This setting
+       has no effect if rename detection is turned off.
 
 diff.renames::
        Whether and how Git detects renames.  If set to "false",
index 8631e36..97d3217 100644 (file)
@@ -188,6 +188,14 @@ endif::git-pull[]
        is specified. This flag forces progress status even if the
        standard error stream is not directed to a terminal.
 
+-o <option>::
+--server-option=<option>::
+       Transmit the given string to the server when communicating using
+       protocol version 2.  The given string must not contain a NUL or LF
+       character.
+       When multiple `--server-option=<option>` are given, they are all
+       sent to the other side in the order listed on the command line.
+
 -4::
 --ipv4::
        Use IPv4 addresses only, ignoring IPv6 addresses.
index d50fa33..45652fe 100644 (file)
@@ -193,7 +193,7 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
        for command-line options).
 
 
-Configuration
+CONFIGURATION
 -------------
 
 The optional configuration variable `core.excludesFile` indicates a path to a
@@ -226,7 +226,7 @@ Because this example lets the shell expand the asterisk (i.e. you are
 listing the files explicitly), it does not consider
 `subdir/git-foo.sh`.
 
-Interactive mode
+INTERACTIVE MODE
 ----------------
 When the command enters the interactive mode, it shows the
 output of the 'status' subcommand, and then goes into its
index 4ebc3d3..6722849 100644 (file)
@@ -113,8 +113,10 @@ explained for the configuration variable `core.quotePath` (see
 linkgit:git-config[1]).
 
 -p<n>::
-       Remove <n> leading slashes from traditional diff paths. The
-       default is 1.
+       Remove <n> leading path components (separated by slashes) from
+       traditional diff paths. E.g., with `-p2`, a patch against
+       `a/dir/file` will be applied directly to `file`. The default is
+       1.
 
 -C<n>::
        Ensure at least <n> lines of surrounding context match before
@@ -240,7 +242,7 @@ When `git apply` is used as a "better GNU patch", the user can pass
 the `--unsafe-paths` option to override this safety check.  This option
 has no effect when `--index` or `--cached` is in use.
 
-Configuration
+CONFIGURATION
 -------------
 
 apply.ignoreWhitespace::
@@ -251,7 +253,7 @@ apply.whitespace::
        When no `--whitespace` flag is given from the command
        line, this configuration item is used as the default.
 
-Submodules
+SUBMODULES
 ----------
 If the patch contains any changes to submodules then 'git apply'
 treats these changes as follows.
index b3084c9..02eccbb 100644 (file)
@@ -287,7 +287,7 @@ CONFIGURATION
 `--list` is used or implied. The default is to use a pager.
 See linkgit:git-config[1].
 
-Examples
+EXAMPLES
 --------
 
 Start development from a known tag::
@@ -318,7 +318,7 @@ See linkgit:git-fetch[1].
 is currently checked out) does not have all commits from the test branch.
 
 
-Notes
+NOTES
 -----
 
 If you are creating a branch that you want to checkout immediately, it is
index 3a8120c..7d6c9dc 100644 (file)
@@ -92,8 +92,8 @@ It is okay to err on the side of caution, causing the bundle file
 to contain objects already in the destination, as these are ignored
 when unpacking at the destination.
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 Assume you want to transfer the history from a repository R1 on machine A
 to another repository R2 on machine B.
index b844b99..a55536f 100644 (file)
@@ -273,7 +273,7 @@ or `--mirror` is given)
 :git-clone: 1
 include::urls.txt[]
 
-Examples
+EXAMPLES
 --------
 
 * Clone from upstream:
index ba90066..37b96c5 100644 (file)
@@ -207,7 +207,7 @@ allowing access over SSH.
 ------
 
 [[dbbackend]]
-Database Backend
+DATABASE BACKEND
 ----------------
 
 'git-cvsserver' uses one database per Git head (i.e. CVS module) to
@@ -321,7 +321,7 @@ git-cvsserver, as described above.
 When these environment variables are set, the corresponding
 command-line arguments may not be used.
 
-Eclipse CVS Client Notes
+ECLIPSE CVS CLIENT NOTES
 ------------------------
 
 To get a checkout with the Eclipse CVS client:
@@ -346,7 +346,7 @@ offer. In that case CVS_SERVER is ignored, and you will have to replace
 the cvs utility on the server with 'git-cvsserver' or manipulate your `.bashrc`
 so that calling 'cvs' effectively calls 'git-cvsserver'.
 
-Clients known to work
+CLIENTS KNOWN TO WORK
 ---------------------
 
 - CVS 1.12.9 on Debian
@@ -354,7 +354,7 @@ Clients known to work
 - Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes)
 - TortoiseCVS
 
-Operations supported
+OPERATIONS SUPPORTED
 --------------------
 
 All the operations required for normal use are supported, including
@@ -424,7 +424,7 @@ For best consistency with 'cvs', it is probably best to override the
 defaults by setting `gitcvs.usecrlfattr` to true,
 and `gitcvs.allBinary` to "guess".
 
-Dependencies
+DEPENDENCIES
 ------------
 'git-cvsserver' depends on DBD::SQLite.
 
index b380677..f4bd815 100644 (file)
@@ -37,14 +37,14 @@ include::diff-options.txt[]
 
 include::diff-format.txt[]
 
-Operating Modes
+OPERATING MODES
 ---------------
 You can choose whether you want to trust the index file entirely
 (using the `--cached` flag) or ask the diff logic to show any files
 that don't match the stat state as being "tentatively changed".  Both
 of these operations are very useful indeed.
 
-Cached Mode
+CACHED MODE
 -----------
 If `--cached` is specified, it allows you to ask:
 
@@ -77,7 +77,7 @@ So doing a `git diff-index --cached` is basically very useful when you are
 asking yourself "what have I already marked for being committed, and
 what's the difference to a previous tree".
 
-Non-cached Mode
+NON-CACHED MODE
 ---------------
 The "non-cached" mode takes a different approach, and is potentially
 the more useful of the two in that what it does can't be emulated with
index 7870e17..2319b2b 100644 (file)
@@ -116,7 +116,7 @@ include::pretty-options.txt[]
 include::pretty-formats.txt[]
 
 
-Limiting Output
+LIMITING OUTPUT
 ---------------
 If you're only interested in differences in a subset of files, for
 example some architecture-specific files, you might do:
index b0c1bb9..7c2c442 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 'git diff' [options] --cached [<commit>] [--] [<path>...]
 'git diff' [options] <commit> <commit> [--] [<path>...]
 'git diff' [options] <blob> <blob>
-'git diff' [options] [--no-index] [--] <path> <path>
+'git diff' [options] --no-index [--] <path> <path>
 
 DESCRIPTION
 -----------
@@ -21,7 +21,7 @@ Show changes between the working tree and the index or a tree, changes
 between the index and a tree, changes between two trees, changes between
 two blob objects, or changes between two files on disk.
 
-'git diff' [--options] [--] [<path>...]::
+'git diff' [options] [--] [<path>...]::
 
        This form is to view the changes you made relative to
        the index (staging area for the next commit).  In other
@@ -29,7 +29,7 @@ two blob objects, or changes between two files on disk.
        further add to the index but you still haven't.  You can
        stage these changes by using linkgit:git-add[1].
 
-'git diff' --no-index [--options] [--] [<path>...]::
+'git diff' [options] --no-index [--] <path> <path>::
 
        This form is to compare the given two paths on the
        filesystem.  You can omit the `--no-index` option when
@@ -38,7 +38,7 @@ two blob objects, or changes between two files on disk.
        or when running the command outside a working tree
        controlled by Git.
 
-'git diff' [--options] --cached [<commit>] [--] [<path>...]::
+'git diff' [options] --cached [<commit>] [--] [<path>...]::
 
        This form is to view the changes you staged for the next
        commit relative to the named <commit>.  Typically you
@@ -48,7 +48,7 @@ two blob objects, or changes between two files on disk.
        <commit> is not given, it shows all staged changes.
        --staged is a synonym of --cached.
 
-'git diff' [--options] <commit> [--] [<path>...]::
+'git diff' [options] <commit> [--] [<path>...]::
 
        This form is to view the changes you have in your
        working tree relative to the named <commit>.  You can
@@ -56,18 +56,18 @@ two blob objects, or changes between two files on disk.
        branch name to compare with the tip of a different
        branch.
 
-'git diff' [--options] <commit> <commit> [--] [<path>...]::
+'git diff' [options] <commit> <commit> [--] [<path>...]::
 
        This is to view the changes between two arbitrary
        <commit>.
 
-'git diff' [--options] <commit>..<commit> [--] [<path>...]::
+'git diff' [options] <commit>..<commit> [--] [<path>...]::
 
        This is synonymous to the previous form.  If <commit> on
        one side is omitted, it will have the same effect as
        using HEAD instead.
 
-'git diff' [--options] <commit>\...<commit> [--] [<path>...]::
+'git diff' [options] <commit>\...<commit> [--] [<path>...]::
 
        This form is to view the changes on the branch containing
        and up to the second <commit>, starting at a common ancestor
index ed57c68..4409859 100644 (file)
@@ -202,7 +202,7 @@ smaller output, and it is usually easy to quickly confirm that there is
 no private data in the stream.
 
 
-Limitations
+LIMITATIONS
 -----------
 
 Since 'git fast-import' cannot tag trees, you will not be
index 3d3d219..cdf696f 100644 (file)
@@ -139,7 +139,7 @@ Performance and Compression Tuning
 fastimport.unpackLimit::
        See linkgit:git-config[1]
 
-Performance
+PERFORMANCE
 -----------
 The design of fast-import allows it to import large projects in a minimum
 amount of memory usage and processing time.  Assuming the frontend
@@ -155,7 +155,7 @@ faster if the source data is stored on a different drive than the
 destination Git repository (due to less IO contention).
 
 
-Development Cost
+DEVELOPMENT COST
 ----------------
 A typical frontend for fast-import tends to weigh in at approximately 200
 lines of Perl/Python/Ruby code.  Most developers have been able to
@@ -165,7 +165,7 @@ an ideal situation, given that most conversion tools are throw-away
 (use once, and never look back).
 
 
-Parallel Operation
+PARALLEL OPERATION
 ------------------
 Like 'git push' or 'git fetch', imports handled by fast-import are safe to
 run alongside parallel `git repack -a -d` or `git gc` invocations,
@@ -186,7 +186,7 @@ this only be used on an otherwise quiet repository.  Using --force
 is not necessary for an initial import into an empty repository.
 
 
-Technical Discussion
+TECHNICAL DISCUSSION
 --------------------
 fast-import tracks a set of branches in memory.  Any branch can be created
 or modified at any point during the import process by sending a
@@ -204,7 +204,7 @@ directory also allows fast-import to run very quickly, as it does not
 need to perform any costly file update operations when switching
 between branches.
 
-Input Format
+INPUT FORMAT
 ------------
 With the exception of raw file data (which Git does not interpret)
 the fast-import input format is text (ASCII) based.  This text based
@@ -1131,7 +1131,7 @@ If the `--done` command-line option or `feature done` command is
 in use, the `done` command is mandatory and marks the end of the
 stream.
 
-Responses To Commands
+RESPONSES TO COMMANDS
 ---------------------
 New objects written by fast-import are not available immediately.
 Most fast-import commands have no visible effect until the next
@@ -1160,7 +1160,7 @@ To avoid deadlock, such frontends must completely consume any
 pending output from `progress`, `ls`, `get-mark`, and `cat-blob` before
 performing writes to fast-import that might block.
 
-Crash Reports
+CRASH REPORTS
 -------------
 If fast-import is supplied invalid input it will terminate with a
 non-zero exit status and create a crash report in the top level of
@@ -1247,7 +1247,7 @@ An example crash:
        END OF CRASH REPORT
 ====
 
-Tips and Tricks
+TIPS AND TRICKS
 ---------------
 The following tips and tricks have been collected from various
 users of fast-import, and are offered here as suggestions.
@@ -1349,7 +1349,7 @@ Your users will feel better knowing how much of the data stream
 has been processed.
 
 
-Packfile Optimization
+PACKFILE OPTIMIZATION
 ---------------------
 When packing a blob fast-import always attempts to deltify against the last
 blob written.  Unless specifically arranged for by the frontend,
@@ -1380,7 +1380,7 @@ to force recomputation of all deltas can significantly reduce the
 final packfile size (30-50% smaller can be quite typical).
 
 
-Memory Utilization
+MEMORY UTILIZATION
 ------------------
 There are a number of factors which affect how much memory fast-import
 requires to perform an import.  Like critical sections of core
@@ -1458,7 +1458,7 @@ and lazy loading of subtrees, allows fast-import to efficiently import
 projects with 2,000+ branches and 45,114+ files in a very limited
 memory footprint (less than 2.7 MiB per active branch).
 
-Signals
+SIGNALS
 -------
 Sending *SIGUSR1* to the 'git fast-import' process ends the current
 packfile early, simulating a `checkpoint` command.  The impatient
index b634043..e6f08ab 100644 (file)
@@ -230,7 +230,7 @@ rewrite, the exit status is `2`.  On any other error, the exit status may be
 any other non-zero value.
 
 
-Examples
+EXAMPLES
 --------
 
 Suppose you want to remove a file (containing confidential information
@@ -288,7 +288,7 @@ git filter-branch --parent-filter \
 or even simpler:
 
 -----------------------------------------------
-echo "$commit-id $graft-id" >> .git/info/grafts
+git replace --graft $commit-id $graft-id
 git filter-branch $graft-id..HEAD
 -----------------------------------------------
 
@@ -406,7 +406,7 @@ git filter-branch --index-filter \
 
 
 
-Checklist for Shrinking a Repository
+CHECKLIST FOR SHRINKING A REPOSITORY
 ------------------------------------
 
 git-filter-branch can be used to get rid of a subset of files,
@@ -445,7 +445,7 @@ warned.
   (or if your git-gc is not new enough to support arguments to
   `--prune`, use `git repack -ad; git prune` instead).
 
-Notes
+NOTES
 -----
 
 git-filter-branch allows you to make complex shell-scripted rewrites
index 44892c4..423b6e0 100644 (file)
@@ -57,8 +57,8 @@ merge.summary::
        Synonym to `merge.log`; this is deprecated and will be removed in
        the future.
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 ---------
 $ git fetch origin master
index 7c8a2ed..24b2dd4 100644 (file)
@@ -9,7 +9,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
 SYNOPSIS
 --------
 [verse]
-'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force]
+'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
 
 DESCRIPTION
 -----------
@@ -56,10 +56,16 @@ single pack using `git repack -d -l`.  Setting the value of `gc.auto`
 to 0 disables automatic packing of loose objects.
 +
 If the number of packs exceeds the value of `gc.autoPackLimit`,
-then existing packs (except those marked with a `.keep` file)
+then existing packs (except those marked with a `.keep` file
+or over `gc.bigPackThreshold` limit)
 are consolidated into a single pack by using the `-A` option of
-'git repack'. Setting `gc.autoPackLimit` to 0 disables
-automatic consolidation of packs.
+'git repack'.
+If the amount of memory is estimated not enough for `git repack` to
+run smoothly and `gc.bigPackThreshold` is not set, the largest
+pack will also be excluded (this is the equivalent of running `git gc`
+with `--keep-base-pack`).
+Setting `gc.autoPackLimit` to 0 disables automatic consolidation of
+packs.
 +
 If houskeeping is required due to many loose objects or packs, all
 other housekeeping tasks (e.g. rerere, working trees, reflog...) will
@@ -84,7 +90,12 @@ be performed as well.
        Force `git gc` to run even if there may be another `git gc`
        instance running on this repository.
 
-Configuration
+--keep-largest-pack::
+       All packs except the largest pack and those marked with a
+       `.keep` files are consolidated into a single pack. When this
+       option is used, `gc.bigPackThreshold` is ignored.
+
+CONFIGURATION
 -------------
 
 The optional configuration variable `gc.reflogExpire` can be
@@ -144,7 +155,7 @@ old a stale working tree should be before `git worktree prune` deletes
 it. Default is "3 months ago".
 
 
-Notes
+NOTES
 -----
 
 'git gc' tries very hard not to delete objects that are referenced
index 18b4947..312409a 100644 (file)
@@ -293,7 +293,7 @@ providing this option will cause it to die.
 For more details about the <pathspec> syntax, see the 'pathspec' entry
 in linkgit:gitglossary[7].
 
-Examples
+EXAMPLES
 --------
 
 `git grep 'time_t' -- '*.[ch]'`::
index 2aceb6f..ea03a4e 100644 (file)
@@ -55,7 +55,7 @@ OPTIONS
        The remote refs to update.
 
 
-Specifying the Refs
+SPECIFYING THE REFS
 -------------------
 
 A '<ref>' specification can be either a single pattern, or a pair
index 5d1e4c8..032613c 100644 (file)
@@ -136,8 +136,8 @@ Using direct mode with SSL:
 .........................
 
 
-EXAMPLE
--------
+EXAMPLES
+--------
 To submit patches using GMail's IMAP interface, first, edit your ~/.gitconfig
 to specify your account settings:
 
index 138edb4..d5b7560 100644 (file)
@@ -93,8 +93,8 @@ OPTIONS
 --max-input-size=<size>::
        Die, if the pack is larger than <size>.
 
-Note
-----
+NOTES
+-----
 
 Once the index has been created, the list of object names is sorted
 and the SHA-1 hash of that list is printed to stdout. If --stdin was
index 3ac3e3a..5298f1b 100644 (file)
@@ -53,7 +53,8 @@ OPTIONS
        Show only ignored files in the output. When showing files in the
        index, print only those matched by an exclude pattern. When
        showing "other" files, show only those matched by an exclude
-       pattern.
+       pattern. Standard ignore rules are not automatically activated,
+       therefore at least one of the `--exclude*` options is required.
 
 -s::
 --stage::
@@ -183,7 +184,7 @@ followed by the  ("attr/<eolattr>").
        Files to show. If no files are given all files which match the other
        specified criteria are shown.
 
-Output
+OUTPUT
 ------
 'git ls-files' just outputs the filenames unless `--stage` is specified in
 which case it outputs:
@@ -208,7 +209,7 @@ quoted as explained for the configuration variable `core.quotePath`
 verbatim and the line is terminated by a NUL byte.
 
 
-Exclude Patterns
+EXCLUDE PATTERNS
 ----------------
 
 'git ls-files' can use a list of "exclude patterns" when
index 6ad1e34..b9fd377 100644 (file)
@@ -70,6 +70,14 @@ OPTIONS
        themselves will not work for refs whose objects have not yet been
        fetched from the remote, and will give a `missing object` error.
 
+-o <option>::
+--server-option=<option>::
+       Transmit the given string to the server when communicating using
+       protocol version 2.  The given string must not contain a NUL or LF
+       character.
+       When multiple `--server-option=<option>` are given, they are all
+       sent to the other side in the order listed on the command line.
+
 <repository>::
        The "remote" repository to query.  This parameter can be
        either a URL or the name of a remote (see the GIT URLS and
index e8e68f5..5cb0eb0 100644 (file)
@@ -61,8 +61,8 @@ OPTIONS
 --always::
        Show uniquely abbreviated commit object as fallback.
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 Given a commit, find out where it is relative to the local refs. Say somebody
 wrote you about that fantastic commit 33db5f4d9027a10e477ccf054b2c1ab94f74c85a.
index d8c8f11..b0abe2c 100644 (file)
@@ -29,8 +29,8 @@ Submit Git changes back to p4 using 'git p4 submit'.  The command
 the updated p4 remote branch.
 
 
-EXAMPLE
--------
+EXAMPLES
+--------
 * Clone a repository:
 +
 ------------
index 81bc490..d95b472 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied]
        [--no-reuse-delta] [--delta-base-offset] [--non-empty]
        [--local] [--incremental] [--window=<n>] [--depth=<n>]
-       [--revs [--unpacked | --all]]
+       [--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
        [--stdout [--filter=<filter-spec>] | base-name]
        [--shallow] [--keep-true-parents] < object-list
 
@@ -96,7 +96,9 @@ base-name::
        it too deep affects the performance on the unpacker
        side, because delta data needs to be applied that many
        times to get to the necessary object.
-       The default value for --window is 10 and --depth is 50.
++
+The default value for --window is 10 and --depth is 50. The maximum
+depth is 4095.
 
 --window-memory=<n>::
        This option provides an additional limit on top of `--window`;
@@ -126,6 +128,13 @@ base-name::
        has a .keep file to be ignored, even if it would have
        otherwise been packed.
 
+--keep-pack=<pack-name>::
+       This flag causes an object already in the given pack to be
+       ignored, even if it would have otherwise been
+       packed. `<pack-name>` is the the pack file name without
+       leading directory (e.g. `pack-123.pack`). The option could be
+       specified multiple times to keep multiple packs.
+
 --incremental::
        This flag causes an object already in a pack to be ignored
        even if it would have otherwise been packed.
@@ -267,6 +276,19 @@ Unexpected missing object will raise an error.
        locally created objects [without .promisor] and objects from the
        promisor remote [with .promisor].)  This is used with partial clone.
 
+--keep-unreachable::
+       Objects unreachable from the refs in packs named with
+       --unpacked= option are added to the resulting pack, in
+       addition to the reachable objects that are not in packs marked
+       with *.keep files. This implies `--revs`.
+
+--pack-loose-unreachable::
+       Pack unreachable loose objects (and their loose counterparts
+       removed). This implies `--revs`.
+
+--unpack-unreachable::
+       Keep unreachable objects in loose form. This implies `--revs`.
+
 SEE ALSO
 --------
 linkgit:git-rev-list[1]
index a37c0af..03552dd 100644 (file)
@@ -56,8 +56,8 @@ OPTIONS
        reachable from any of our references, keep objects
        reachable from listed <head>s.
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 To prune objects not used by your repository or another that
 borrows from your repository via its
@@ -67,7 +67,7 @@ borrows from your repository via its
 $ git prune $(cd ../another && git rev-parse --all)
 ------------
 
-Notes
+NOTES
 -----
 
 In most cases, users will not need to call 'git prune' directly, but
index ce05b7a..4e0ad6f 100644 (file)
@@ -101,13 +101,17 @@ Options related to merging
 include::merge-options.txt[]
 
 -r::
---rebase[=false|true|preserve|interactive]::
+--rebase[=false|true|merges|preserve|interactive]::
        When true, rebase the current branch on top of the upstream
        branch after fetching. If there is a remote-tracking branch
        corresponding to the upstream branch and the upstream branch
        was rebased since last fetched, the rebase uses that information
        to avoid rebasing non-local changes.
 +
+When set to `merges`, rebase using `git rebase --rebase-merges` so that
+the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
 When set to preserve, rebase with the `--preserve-merges` option passed
 to `git rebase` so that locally created merge commits will not be flattened.
 +
index 34410f9..55277a9 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
           [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
-          [-u | --set-upstream] [--push-option=<string>]
+          [-u | --set-upstream] [-o <string> | --push-option=<string>]
           [--[no-]signed|--signed=(true|false|if-asked)]
           [--force-with-lease[=<refname>[:<expect>]]]
           [--no-verify] [<repository> [<refspec>...]]
@@ -123,6 +123,7 @@ already exists on the remote side.
        will be tab-separated and sent to stdout instead of stderr.  The full
        symbolic names of the refs will be given.
 
+-d::
 --delete::
        All listed refs are deleted from the remote repository. This is
        the same as prefixing all refs with a colon.
@@ -423,7 +424,7 @@ reason::
        refs, no explanation is needed. For a failed ref, the reason for
        failure is described.
 
-Note about fast-forwards
+NOTE ABOUT FAST-FORWARDS
 ------------------------
 
 When an update changes a branch (or more in general, a ref) that used to
@@ -510,7 +511,7 @@ overwrite it. In other words, "git push --force" is a method reserved for
 a case where you do mean to lose history.
 
 
-Examples
+EXAMPLES
 --------
 
 `git push`::
index f2a07d5..5c70bc2 100644 (file)
@@ -132,7 +132,7 @@ OPTIONS
        The id of the tree object(s) to be read/merged.
 
 
-Merging
+MERGING
 -------
 If `-m` is specified, 'git read-tree' can perform 3 kinds of
 merge, a single tree merge if only 1 tree is given, a
@@ -382,7 +382,7 @@ middle of doing, and when your working tree is ready (i.e. you
 have finished your work-in-progress), attempt the merge again.
 
 
-Sparse checkout
+SPARSE CHECKOUT
 ---------------
 
 "Sparse checkout" allows populating the working directory sparsely.
index dd85206..bd5ecff 100644 (file)
@@ -379,6 +379,33 @@ The commit list format can be changed by setting the configuration option
 rebase.instructionFormat.  A customized instruction format will automatically
 have the long commit hash prepended to the format.
 
+-r::
+--rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
+       By default, a rebase will simply drop merge commits from the todo
+       list, and put the rebased commits into a single, linear branch.
+       With `--rebase-merges`, the rebase will instead try to preserve
+       the branching structure within the commits that are to be rebased,
+       by recreating the merge commits. Any resolved merge conflicts or
+       manual amendments in these merge commits will have to be
+       resolved/re-applied manually.
++
+By default, or when `no-rebase-cousins` was specified, commits which do not
+have `<upstream>` as direct ancestor will keep their original branch point,
+i.e. commits that would be excluded by gitlink:git-log[1]'s
+`--ancestry-path` option will keep their original ancestry by default. If
+the `rebase-cousins` mode is turned on, such commits are instead rebased
+onto `<upstream>` (or `<onto>`, if specified).
++
+The `--rebase-merges` mode is similar in spirit to `--preserve-merges`, but
+in contrast to that option works well in interactive rebases: commits can be
+reordered, inserted and dropped at will.
++
+It is currently only possible to recreate the merge commits using the
+`recursive` merge strategy; Different merge strategies can be used only via
+explicit `exec git merge -s <strategy> [...]` commands.
++
+See also REBASING MERGES below.
+
 -p::
 --preserve-merges::
        Recreate merge commits instead of flattening the history by replaying
@@ -776,12 +803,146 @@ The ripple effect of a "hard case" recovery is especially bad:
 'everyone' downstream from 'topic' will now have to perform a "hard
 case" recovery too!
 
+REBASING MERGES
+-----------------
+
+The interactive rebase command was originally designed to handle
+individual patch series. As such, it makes sense to exclude merge
+commits from the todo list, as the developer may have merged the
+then-current `master` while working on the branch, only to rebase
+all the commits onto `master` eventually (skipping the merge
+commits).
+
+However, there are legitimate reasons why a developer may want to
+recreate merge commits: to keep the branch structure (or "commit
+topology") when working on multiple, inter-related branches.
+
+In the following example, the developer works on a topic branch that
+refactors the way buttons are defined, and on another topic branch
+that uses that refactoring to implement a "Report a bug" button. The
+output of `git log --graph --format=%s -5` may look like this:
+
+------------
+*   Merge branch 'report-a-bug'
+|\
+| * Add the feedback button
+* | Merge branch 'refactor-button'
+|\ \
+| |/
+| * Use the Button class for all buttons
+| * Extract a generic Button class from the DownloadButton one
+------------
+
+The developer might want to rebase those commits to a newer `master`
+while keeping the branch topology, for example when the first topic
+branch is expected to be integrated into `master` much earlier than the
+second one, say, to resolve merge conflicts with changes to the
+DownloadButton class that made it into `master`.
+
+This rebase can be performed using the `--rebase-merges` option.
+It will generate a todo list looking like this:
+
+------------
+label onto
+
+# Branch: refactor-button
+reset onto
+pick 123456 Extract a generic Button class from the DownloadButton one
+pick 654321 Use the Button class for all buttons
+label refactor-button
+
+# Branch: report-a-bug
+reset refactor-button # Use the Button class for all buttons
+pick abcdef Add the feedback button
+label report-a-bug
+
+reset onto
+merge -C a1b2c3 refactor-button # Merge 'refactor-button'
+merge -C 6f5e4d report-a-bug # Merge 'report-a-bug'
+------------
+
+In contrast to a regular interactive rebase, there are `label`, `reset`
+and `merge` commands in addition to `pick` ones.
+
+The `label` command associates a label with the current HEAD when that
+command is executed. These labels are created as worktree-local refs
+(`refs/rewritten/<label>`) that will be deleted when the rebase
+finishes. That way, rebase operations in multiple worktrees linked to
+the same repository do not interfere with one another. If the `label`
+command fails, it is rescheduled immediately, with a helpful message how
+to proceed.
+
+The `reset` command resets the HEAD, index and worktree to the specified
+revision. It is isimilar to an `exec git reset --hard <label>`, but
+refuses to overwrite untracked files. If the `reset` command fails, it is
+rescheduled immediately, with a helpful message how to edit the todo list
+(this typically happens when a `reset` command was inserted into the todo
+list manually and contains a typo).
+
+The `merge` command will merge the specified revision into whatever is
+HEAD at that time. With `-C <original-commit>`, the commit message of
+the specified merge commit will be used. When the `-C` is changed to
+a lower-case `-c`, the message will be opened in an editor after a
+successful merge so that the user can edit the message.
+
+If a `merge` command fails for any reason other than merge conflicts (i.e.
+when the merge operation did not even start), it is rescheduled immediately.
+
+At this time, the `merge` command will *always* use the `recursive`
+merge strategy, with no way to choose a different one. To work around
+this, an `exec` command can be used to call `git merge` explicitly,
+using the fact that the labels are worktree-local refs (the ref
+`refs/rewritten/onto` would correspond to the label `onto`, for example).
+
+Note: the first command (`label onto`) labels the revision onto which
+the commits are rebased; The name `onto` is just a convention, as a nod
+to the `--onto` option.
+
+It is also possible to introduce completely new merge commits from scratch
+by adding a command of the form `merge <merge-head>`. This form will
+generate a tentative commit message and always open an editor to let the
+user edit it. This can be useful e.g. when a topic branch turns out to
+address more than a single concern and wants to be split into two or
+even more topic branches. Consider this todo list:
+
+------------
+pick 192837 Switch from GNU Makefiles to CMake
+pick 5a6c7e Document the switch to CMake
+pick 918273 Fix detection of OpenSSL in CMake
+pick afbecd http: add support for TLS v1.3
+pick fdbaec Fix detection of cURL in CMake on Windows
+------------
+
+The one commit in this list that is not related to CMake may very well
+have been motivated by working on fixing all those bugs introduced by
+switching to CMake, but it addresses a different concern. To split this
+branch into two topic branches, the todo list could be edited like this:
+
+------------
+label onto
+
+pick afbecd http: add support for TLS v1.3
+label tlsv1.3
+
+reset onto
+pick 192837 Switch from GNU Makefiles to CMake
+pick 918273 Fix detection of OpenSSL in CMake
+pick fdbaec Fix detection of cURL in CMake on Windows
+pick 5a6c7e Document the switch to CMake
+label cmake
+
+reset onto
+merge tlsv1.3
+merge cmake
+------------
+
 BUGS
 ----
 The todo list presented by `--preserve-merges --interactive` does not
 represent the topology of the revision graph.  Editing commits and
 rewording their commit messages should work fine, but attempts to
-reorder commits tend to produce counterintuitive results.
+reorder commits tend to produce counterintuitive results. Use
+`--rebase-merges` in such scenarios instead.
 
 For example, an attempt to rearrange
 ------------
index 86a4b32..dedf97e 100644 (file)
@@ -41,7 +41,7 @@ OPTIONS
 <directory>::
        The repository to sync into.
 
-pre-receive Hook
+PRE-RECEIVE HOOK
 ----------------
 Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists
 and is executable, it will be invoked once with no parameters.  The
@@ -116,7 +116,7 @@ bail out if the update is not to be supported.
 
 See the notes on the quarantine environment below.
 
-update Hook
+UPDATE HOOK
 -----------
 Before each ref is updated, if $GIT_DIR/hooks/update file exists
 and is executable, it is invoked once per ref, with three parameters:
@@ -138,7 +138,7 @@ ensure the ref will actually be updated, it is only a prerequisite.
 As such it is not a good idea to send notices (e.g. email) from
 this hook.  Consider using the post-receive hook instead.
 
-post-receive Hook
+POST-RECEIVE HOOK
 -----------------
 After all refs were updated (or attempted to be updated), if any
 ref update was successful, and if $GIT_DIR/hooks/post-receive
@@ -198,7 +198,7 @@ after it was updated by 'git-receive-pack', but before the hook was able
 to evaluate it.  It is recommended that hooks rely on sha1-new
 rather than the current value of refname.
 
-post-update Hook
+POST-UPDATE HOOK
 ----------------
 After all other processing, if at least one ref was updated, and
 if $GIT_DIR/hooks/post-update file exists and is executable, then
@@ -216,7 +216,7 @@ if the repository is packed and is served via a dumb transport.
        exec git update-server-info
 
 
-Quarantine Environment
+QUARANTINE ENVIRONMENT
 ----------------------
 
 When `receive-pack` takes in objects, they are placed into a temporary
index b25d0b5..3fc5d94 100644 (file)
@@ -55,14 +55,14 @@ some tunnel.
        the vhost field in the git:// service request (to rest of the argument).
        Default is not to send vhost in such request (if sent).
 
-ENVIRONMENT VARIABLES:
-----------------------
+ENVIRONMENT VARIABLES
+---------------------
 
 GIT_TRANSLOOP_DEBUG::
        If set, prints debugging information about various reads/writes.
 
-ENVIRONMENT VARIABLES PASSED TO COMMAND:
-----------------------------------------
+ENVIRONMENT VARIABLES PASSED TO COMMAND
+---------------------------------------
 
 GIT_EXT_SERVICE::
        Set to long name (git-upload-pack, etc...) of service helper needs
@@ -73,8 +73,8 @@ GIT_EXT_SERVICE_NOPREFIX::
        to invoke.
 
 
-EXAMPLES:
----------
+EXAMPLES
+--------
 This remote helper is transparently used by Git when
 you use commands such as "git fetch <URL>", "git clone <URL>",
 , "git push <URL>" or "git remote add <nick> <URL>", where <URL>
index 4feddc0..595948d 100644 (file)
@@ -203,7 +203,7 @@ The remote configuration is achieved using the `remote.origin.url` and
 `remote.origin.fetch` configuration variables.  (See
 linkgit:git-config[1]).
 
-Examples
+EXAMPLES
 --------
 
 * Add a new remote, fetch, and check out a branch from it
index ae750e9..d90e790 100644 (file)
@@ -9,7 +9,7 @@ git-repack - Pack unpacked objects in a repository
 SYNOPSIS
 --------
 [verse]
-'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [--window=<n>] [--depth=<n>] [--threads=<n>]
+'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]
 
 DESCRIPTION
 -----------
@@ -90,7 +90,9 @@ other objects in that pack they already have locally.
        space. `--depth` limits the maximum delta depth; making it too deep
        affects the performance on the unpacker side, because delta data needs
        to be applied that many times to get to the necessary object.
-       The default value for --window is 10 and --depth is 50.
++
+The default value for --window is 10 and --depth is 50. The maximum
+depth is 4095.
 
 --threads=<n>::
        This option is passed through to `git pack-objects`.
@@ -133,6 +135,13 @@ other objects in that pack they already have locally.
        with `-b` or `repack.writeBitmaps`, as it ensures that the
        bitmapped packfile has the necessary objects.
 
+--keep-pack=<pack-name>::
+       Exclude the given pack from repacking. This is the equivalent
+       of having `.keep` file on the pack. `<pack-name>` is the the
+       pack file name without leading directory (e.g. `pack-123.pack`).
+       The option could be specified multiple times to keep multiple
+       packs.
+
 --unpack-unreachable=<when>::
        When loosening unreachable objects, do not bother loosening any
        objects older than `<when>`. This can be used to optimize out
index e5c57ae..246dc99 100644 (file)
@@ -11,6 +11,7 @@ SYNOPSIS
 'git replace' [-f] <object> <replacement>
 'git replace' [-f] --edit <object>
 'git replace' [-f] --graft <commit> [<parent>...]
+'git replace' [-f] --convert-graft-file
 'git replace' -d <object>...
 'git replace' [--format=<format>] [-l [<pattern>]]
 
@@ -87,9 +88,13 @@ OPTIONS
        content as <commit> except that its parents will be
        [<parent>...] instead of <commit>'s parents. A replacement ref
        is then created to replace <commit> with the newly created
-       commit. See contrib/convert-grafts-to-replace-refs.sh for an
-       example script based on this option that can convert grafts to
-       replace refs.
+       commit. Use `--convert-graft-file` to convert a
+       `$GIT_DIR/info/grafts` file and use replace refs instead.
+
+--convert-graft-file::
+       Creates graft commits for all entries in `$GIT_DIR/info/grafts`
+       and deletes that file upon success. The purpose is to help users
+       with transitioning off of the now-deprecated graft file.
 
 -l <pattern>::
 --list <pattern>::
index c32cb0b..4d4392d 100644 (file)
@@ -46,8 +46,8 @@ ref that is different from the ref you have locally, you can use the
 its remote name.
 
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 Imagine that you built your work on your `master` branch on top of
 the `v1.0` release, and want it to be integrated to the project.
index 60cf96f..464c15b 100644 (file)
@@ -458,8 +458,8 @@ sendemail.confirm::
        one of 'always', 'never', 'cc', 'compose', or 'auto'. See `--confirm`
        in the previous section for the meaning of these values.
 
-EXAMPLE
--------
+EXAMPLES
+--------
 Use gmail as the smtp server
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 To use 'git send-email' to send your patches through the GMail SMTP server,
index f51c649..44fd146 100644 (file)
@@ -99,7 +99,7 @@ be in a separate packet, and the list must end with a flush packet.
        The remote refs to update.
 
 
-Specifying the Refs
+SPECIFYING THE REFS
 -------------------
 
 There are three ways to specify which refs to update on the
index 54cf256..11361f3 100644 (file)
@@ -62,8 +62,8 @@ permissions.
 If a `no-interactive-login` command exists, then it is run and the
 interactive shell is aborted.
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 To disable interactive logins, displaying a greeting instead:
 
index 7818e0f..262db04 100644 (file)
@@ -173,8 +173,8 @@ The "fixes" branch adds one commit "Introduce "reset type" flag to
 The current branch is "master".
 
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 If you keep your primary branches immediately under
 `refs/heads`, and topic branches in subdirectories of
index c0aa871..d28e615 100644 (file)
@@ -120,8 +120,8 @@ $ git show-ref --heads --hash
 ...
 -----------------------------------------------------------------------------
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 To show all references called "master", whether tags or heads or anything
 else, and regardless of how deep in the reference naming hierarchy they are,
index e73ef54..0e1695d 100644 (file)
@@ -77,7 +77,7 @@ EXAMPLES
        Concatenates the contents of said Makefiles in the head
        of the branch `master`.
 
-Discussion
+DISCUSSION
 ----------
 
 include::i18n.txt[]
index c16e27e..c4467ff 100644 (file)
@@ -135,6 +135,16 @@ ignored, then the directory is not shown, but all contents are shown.
        Display or do not display detailed ahead/behind counts for the
        branch relative to its upstream branch.  Defaults to true.
 
+--renames::
+--no-renames::
+       Turn on/off rename detection regardless of user configuration.
+       See also linkgit:git-diff[1] `--no-renames`.
+
+--find-renames[=<n>]::
+       Turn on rename detection, optionally setting the similarity
+       threshold.
+       See also linkgit:git-diff[1] `--find-renames`.
+
 <pathspec>...::
        See the 'pathspec' entry in linkgit:gitglossary[7].
 
index 630999f..4a5cc38 100644 (file)
@@ -239,6 +239,13 @@ OPTIONS
 --quiet::
        Only print error messages.
 
+--progress::
+       This option is only valid for add and update commands.
+       Progress status is reported on the standard error stream
+       by default when it is attached to a terminal, unless -q
+       is specified. This flag forces progress status even if the
+       standard error stream is not directed to a terminal.
+
 --all::
        This option is only valid for the deinit command. Unregister all
        submodules in the working tree.
@@ -362,7 +369,15 @@ the submodule itself.
        this option will be passed to the linkgit:git-clone[1] command.
 +
 *NOTE*: Do *not* use this option unless you have read the note
-for linkgit:git-clone[1]'s `--reference` and `--shared` options carefully.
+for linkgit:git-clone[1]'s `--reference`, `--shared`, and `--dissociate`
+options carefully.
+
+--dissociate::
+       This option is only valid for add and update commands.  These
+       commands sometimes need to clone a remote repository. In this case,
+       this option will be passed to the linkgit:git-clone[1] command.
++
+*NOTE*: see the NOTE for the `--reference` option.
 
 --recursive::
        This option is only valid for foreach, update, status and sync commands.
index d59379e..e961595 100644 (file)
@@ -707,7 +707,7 @@ creating the branch or tag.
 config key: svn.useLogAuthor
 
 --add-author-from::
-       When committing to svn from Git (as part of 'commit-diff', 'set-tree' or 'dcommit'
+       When committing to svn from Git (as part of 'set-tree' or 'dcommit'
        operations), if the existing log message doesn't already have a
        `From:` or `Signed-off-by:` line, append a `From:` line based on the
        Git commit's author string.  If you use this, then `--use-log-author`
index 3897a59..4e8e762 100644 (file)
@@ -228,7 +228,7 @@ will remove the intended effect of the option.
        cleaner names.
        The same applies to directories ending '/' and paths with '//'
 
-Using --refresh
+USING --REFRESH
 ---------------
 `--refresh` does not calculate a new sha1 file or bring the index
 up to date for mode/content changes. But what it *does* do is to
@@ -239,7 +239,7 @@ the stat entry is out of date.
 For example, you'd want to do this after doing a 'git read-tree', to link
 up the stat index details with the proper files.
 
-Using --cacheinfo or --info-only
+USING --CACHEINFO OR --INFO-ONLY
 --------------------------------
 `--cacheinfo` is used to register a file that is not in the
 current working directory.  This is useful for minimum-checkout
@@ -261,7 +261,7 @@ useful when the file is available, but you do not wish to update the
 object database.
 
 
-Using --index-info
+USING --INDEX-INFO
 ------------------
 
 `--index-info` is a more powerful mechanism that lets you feed
@@ -317,7 +317,7 @@ $ git ls-files -s
 ------------
 
 
-Using ``assume unchanged'' bit
+USING ``ASSUME UNCHANGED'' BIT
 ------------------------------
 
 Many operations in Git depend on your filesystem to have an
@@ -350,7 +350,7 @@ the index (use `git update-index --really-refresh` if you want
 to mark them as "assume unchanged").
 
 
-Examples
+EXAMPLES
 --------
 To update and refresh only the files already checked out:
 
@@ -387,7 +387,7 @@ M foo.c
 <9> now it checks with lstat(2) and finds it has been changed.
 
 
-Skip-worktree bit
+SKIP-WORKTREE BIT
 -----------------
 
 Skip-worktree bit can be defined in one (long) sentence: When reading
@@ -407,7 +407,7 @@ Although this bit looks similar to assume-unchanged bit, its goal is
 different from assume-unchanged bit's. Skip-worktree also takes
 precedence over assume-unchanged bit when both are set.
 
-Split index
+SPLIT INDEX
 -----------
 
 This mode is designed for repositories with very large indexes, and
@@ -432,7 +432,7 @@ To avoid deleting a shared index file that is still used, its
 modification time is updated to the current time everytime a new split
 index based on the shared index file is either created or read from.
 
-Untracked cache
+UNTRACKED CACHE
 ---------------
 
 This cache is meant to speed up commands that involve determining
@@ -490,7 +490,7 @@ As with the bug described above the solution is to one-off do a "git
 status" run with `core.untrackedCache=false` to flush out the leftover
 bad data.
 
-File System Monitor
+FILE SYSTEM MONITOR
 -------------------
 
 This feature is intended to speed up git operations for repos that have
@@ -518,7 +518,7 @@ file system monitor is added to or removed from the index the next time
 a command reads the index. When `--[no-]fsmonitor` are used, the file
 system monitor is immediately added to or removed from the index.
 
-Configuration
+CONFIGURATION
 -------------
 
 The command honors `core.filemode` configuration variable.  If
index 969bfab..bc8fdfd 100644 (file)
@@ -120,7 +120,7 @@ modifications are performed.  Note that while each individual
 <ref> is updated or deleted atomically, a concurrent reader may
 still see a subset of the modifications.
 
-Logging Updates
+LOGGING UPDATES
 ---------------
 If config parameter "core.logAllRefUpdates" is true and the ref is one under
 "refs/heads/", "refs/remotes/", "refs/notes/", or the symbolic ref HEAD; or
index 44ff954..6072f93 100644 (file)
@@ -23,14 +23,14 @@ OPTIONS
        as well. (However, the configuration variables listing functionality
        is deprecated in favor of `git config -l`.)
 
-EXAMPLE
+EXAMPLES
 --------
        $ git var GIT_AUTHOR_IDENT
        Eric W. Biederman <ebiederm@lnxi.com> 1121223278 -0600
 
 
 VARIABLES
-----------
+---------
 GIT_AUTHOR_IDENT::
     The author of a piece of code.
 
index 2d6b09a..a4ec25b 100644 (file)
@@ -84,7 +84,7 @@ variable exists then 'git web{litdd}browse' will treat the specified tool
 as a custom command and will use a shell eval to run the command with
 the URLs passed as arguments.
 
-Note about konqueror
+NOTE ABOUT KONQUEROR
 --------------------
 
 When 'konqueror' is specified by a command-line option or a
index 9920d9c..afc6576 100644 (file)
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, the new worktree is associated with a branch
+(call it `<branch>`) named after `$(basename <path>)`.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` does exist, it will be
+checked out in the new worktree, if it's not checked out anywhere
+else, otherwise the command will refuse to create the worktree (unless
+`--force` is used).
 
 list::
 
index 4767860..c662f41 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git' [--version] [--help] [-C <path>] [-c <name>=<value>]
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
-    [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
+    [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
     [--super-prefix=<path>]
     <command> [<args>]
@@ -103,6 +103,7 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config
        configuration options (see the "Configuration Mechanism" section
        below).
 
+-P::
 --no-pager::
        Do not pipe Git output into a pager.
 
index ee210be..b72936a 100644 (file)
@@ -1229,8 +1229,8 @@ to:
 ------------
 
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
 If you have these three `gitattributes` file:
 
index f877f7b..e3c283a 100644 (file)
@@ -31,7 +31,7 @@ Hooks can get their arguments via the environment, command-line
 arguments, and stdin. See the documentation for each hook below for
 details.
 
-'git init' may copy hooks to the new repository, depending on its
+`git init` may copy hooks to the new repository, depending on its
 configuration. See the "TEMPLATE DIRECTORY" section in
 linkgit:git-init[1] for details. When the rest of this document refers
 to "default hooks" it's talking about the default template shipped
@@ -45,9 +45,9 @@ HOOKS
 applypatch-msg
 ~~~~~~~~~~~~~~
 
-This hook is invoked by 'git am'.  It takes a single
+This hook is invoked by linkgit:git-am[1].  It takes a single
 parameter, the name of the file that holds the proposed commit
-log message.  Exiting with a non-zero status causes 'git am' to abort
+log message.  Exiting with a non-zero status causes `git am` to abort
 before applying the patch.
 
 The hook is allowed to edit the message file in place, and can
@@ -61,7 +61,7 @@ The default 'applypatch-msg' hook, when enabled, runs the
 pre-applypatch
 ~~~~~~~~~~~~~~
 
-This hook is invoked by 'git am'.  It takes no parameter, and is
+This hook is invoked by linkgit:git-am[1].  It takes no parameter, and is
 invoked after the patch is applied, but before a commit is made.
 
 If it exits with non-zero status, then the working tree will not be
@@ -76,33 +76,33 @@ The default 'pre-applypatch' hook, when enabled, runs the
 post-applypatch
 ~~~~~~~~~~~~~~~
 
-This hook is invoked by 'git am'.  It takes no parameter,
+This hook is invoked by linkgit:git-am[1].  It takes no parameter,
 and is invoked after the patch is applied and a commit is made.
 
 This hook is meant primarily for notification, and cannot affect
-the outcome of 'git am'.
+the outcome of `git am`.
 
 pre-commit
 ~~~~~~~~~~
 
-This hook is invoked by 'git commit', and can be bypassed
+This hook is invoked by linkgit:git-commit[1], and can be bypassed
 with the `--no-verify` option.  It takes no parameters, and is
 invoked before obtaining the proposed commit log message and
 making a commit.  Exiting with a non-zero status from this script
-causes the 'git commit' command to abort before creating a commit.
+causes the `git commit` command to abort before creating a commit.
 
 The default 'pre-commit' hook, when enabled, catches introduction
 of lines with trailing whitespaces and aborts the commit when
 such a line is found.
 
-All the 'git commit' hooks are invoked with the environment
+All the `git commit` hooks are invoked with the environment
 variable `GIT_EDITOR=:` if the command will not bring up an editor
 to modify the commit message.
 
 prepare-commit-msg
 ~~~~~~~~~~~~~~~~~~
 
-This hook is invoked by 'git commit' right after preparing the
+This hook is invoked by linkgit:git-commit[1] right after preparing the
 default log message, and before the editor is started.
 
 It takes one to three parameters.  The first is the name of the file
@@ -114,7 +114,7 @@ commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
 (if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
 a commit SHA-1 (if a `-c`, `-C` or `--amend` option was given).
 
-If the exit status is non-zero, 'git commit' will abort.
+If the exit status is non-zero, `git commit` will abort.
 
 The purpose of the hook is to edit the message file in place, and
 it is not suppressed by the `--no-verify` option.  A non-zero exit
@@ -127,7 +127,7 @@ help message found in the commented portion of the commit template.
 commit-msg
 ~~~~~~~~~~
 
-This hook is invoked by 'git commit' and 'git merge', and can be
+This hook is invoked by linkgit:git-commit[1] and linkgit:git-merge[1], and can be
 bypassed with the `--no-verify` option.  It takes a single parameter,
 the name of the file that holds the proposed commit log message.
 Exiting with a non-zero status causes the command to abort.
@@ -143,16 +143,16 @@ The default 'commit-msg' hook, when enabled, detects duplicate
 post-commit
 ~~~~~~~~~~~
 
-This hook is invoked by 'git commit'. It takes no parameters, and is
+This hook is invoked by linkgit:git-commit[1]. It takes no parameters, and is
 invoked after a commit is made.
 
 This hook is meant primarily for notification, and cannot affect
-the outcome of 'git commit'.
+the outcome of `git commit`.
 
 pre-rebase
 ~~~~~~~~~~
 
-This hook is called by 'git rebase' and can be used to prevent a
+This hook is called by linkgit:git-rebase[1] and can be used to prevent a
 branch from getting rebased.  The hook may be called with one or
 two parameters.  The first parameter is the upstream from which
 the series was forked.  The second parameter is the branch being
@@ -161,17 +161,17 @@ rebased, and is not set when rebasing the current branch.
 post-checkout
 ~~~~~~~~~~~~~
 
-This hook is invoked when a 'git checkout' is run after having updated the
+This hook is invoked when a linkgit:git-checkout[1] is run after having updated the
 worktree.  The hook is given three parameters: the ref of the previous HEAD,
 the ref of the new HEAD (which may or may not have changed), and a flag
 indicating whether the checkout was a branch checkout (changing branches,
 flag=1) or a file checkout (retrieving a file from the index, flag=0).
-This hook cannot affect the outcome of 'git checkout'.
+This hook cannot affect the outcome of `git checkout`.
 
-It is also run after 'git clone', unless the --no-checkout (-n) option is
+It is also run after linkgit:git-clone[1], unless the `--no-checkout` (`-n`) option is
 used. The first parameter given to the hook is the null-ref, the second the
-ref of the new HEAD and the flag is always 1. Likewise for 'git worktree add'
-unless --no-checkout is used.
+ref of the new HEAD and the flag is always 1. Likewise for `git worktree add`
+unless `--no-checkout` is used.
 
 This hook can be used to perform repository validity checks, auto-display
 differences from the previous HEAD if different, or set working dir metadata
@@ -180,10 +180,10 @@ properties.
 post-merge
 ~~~~~~~~~~
 
-This hook is invoked by 'git merge', which happens when a 'git pull'
+This hook is invoked by linkgit:git-merge[1], which happens when a `git pull`
 is done on a local repository.  The hook takes a single parameter, a status
 flag specifying whether or not the merge being done was a squash merge.
-This hook cannot affect the outcome of 'git merge' and is not executed,
+This hook cannot affect the outcome of `git merge` and is not executed,
 if the merge failed due to conflicts.
 
 This hook can be used in conjunction with a corresponding pre-commit hook to
@@ -194,10 +194,10 @@ for an example of how to do this.
 pre-push
 ~~~~~~~~
 
-This hook is called by 'git push' and can be used to prevent a push from taking
-place.  The hook is called with two parameters which provide the name and
-location of the destination remote, if a named remote is not being used both
-values will be the same.
+This hook is called by linkgit:git-push[1] and can be used to prevent
+a push from taking place.  The hook is called with two parameters
+which provide the name and location of the destination remote, if a
+named remote is not being used both values will be the same.
 
 Information about what is to be pushed is provided on the hook's standard
 input with lines of the form:
@@ -216,7 +216,7 @@ SHA-1>` will be 40 `0`.  If the local commit was specified by something other
 than a name which could be expanded (such as `HEAD~`, or a SHA-1) it will be
 supplied as it was originally given.
 
-If this hook exits with a non-zero status, 'git push' will abort without
+If this hook exits with a non-zero status, `git push` will abort without
 pushing anything.  Information about why the push is rejected may be sent
 to the user by writing to standard error.
 
@@ -224,8 +224,8 @@ to the user by writing to standard error.
 pre-receive
 ~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' when it reacts to
-'git push' and updates reference(s) in its repository.
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
 Just before starting to update refs on the remote repository, the
 pre-receive hook is invoked.  Its exit status determines the success
 or failure of the update.
@@ -246,7 +246,7 @@ updated. If the hook exits with zero, updating of individual refs can
 still be prevented by the <<update,'update'>> hook.
 
 Both standard output and standard error output are forwarded to
-'git send-pack' on the other end, so you can simply `echo` messages
+`git send-pack` on the other end, so you can simply `echo` messages
 for the user.
 
 The number of push options given on the command line of
@@ -265,8 +265,8 @@ linkgit:git-receive-pack[1] for some caveats.
 update
 ~~~~~~
 
-This hook is invoked by 'git-receive-pack' when it reacts to
-'git push' and updates reference(s) in its repository.
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
 Just before updating the ref on the remote repository, the update hook
 is invoked.  Its exit status determines the success or failure of
 the ref update.
@@ -279,7 +279,7 @@ three parameters:
  - and the new object name to be stored in the ref.
 
 A zero exit from the update hook allows the ref to be updated.
-Exiting with a non-zero status prevents 'git-receive-pack'
+Exiting with a non-zero status prevents `git receive-pack`
 from updating that ref.
 
 This hook can be used to prevent 'forced' update on certain refs by
@@ -299,7 +299,7 @@ membership. See linkgit:git-shell[1] for how you might use the login
 shell to restrict the user's access to only git commands.
 
 Both standard output and standard error output are forwarded to
-'git send-pack' on the other end, so you can simply `echo` messages
+`git send-pack` on the other end, so you can simply `echo` messages
 for the user.
 
 The default 'update' hook, when enabled--and with
@@ -310,8 +310,8 @@ unannotated tags to be pushed.
 post-receive
 ~~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' when it reacts to
-'git push' and updates reference(s) in its repository.
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
 It executes on the remote repository once after all the refs have
 been updated.
 
@@ -320,7 +320,7 @@ arguments, but gets the same information as the
 <<pre-receive,'pre-receive'>>
 hook does on its standard input.
 
-This hook does not affect the outcome of 'git-receive-pack', as it
+This hook does not affect the outcome of `git receive-pack`, as it
 is called after the real work is done.
 
 This supersedes the <<post-update,'post-update'>> hook in that it gets
@@ -328,7 +328,7 @@ both old and new values of all the refs in addition to their
 names.
 
 Both standard output and standard error output are forwarded to
-'git send-pack' on the other end, so you can simply `echo` messages
+`git send-pack` on the other end, so you can simply `echo` messages
 for the user.
 
 The default 'post-receive' hook is empty, but there is
@@ -349,8 +349,8 @@ will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
 post-update
 ~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' when it reacts to
-'git push' and updates reference(s) in its repository.
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
 It executes on the remote repository once after all the refs have
 been updated.
 
@@ -358,7 +358,7 @@ It takes a variable number of parameters, each of which is the
 name of ref that was actually updated.
 
 This hook is meant primarily for notification, and cannot affect
-the outcome of 'git-receive-pack'.
+the outcome of `git receive-pack`.
 
 The 'post-update' hook can tell what are the heads that were pushed,
 but it does not know what their original and updated values are,
@@ -368,20 +368,20 @@ updated values of the refs. You might consider it instead if you need
 them.
 
 When enabled, the default 'post-update' hook runs
-'git update-server-info' to keep the information used by dumb
+`git update-server-info` to keep the information used by dumb
 transports (e.g., HTTP) up to date.  If you are publishing
 a Git repository that is accessible via HTTP, you should
 probably enable this hook.
 
 Both standard output and standard error output are forwarded to
-'git send-pack' on the other end, so you can simply `echo` messages
+`git send-pack` on the other end, so you can simply `echo` messages
 for the user.
 
 push-to-checkout
 ~~~~~~~~~~~~~~~~
 
-This hook is invoked by 'git-receive-pack' when it reacts to
-'git push' and updates reference(s) in its repository, and when
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository, and when
 the push tries to update the branch that is currently checked out
 and the `receive.denyCurrentBranch` configuration variable is set to
 `updateInstead`.  Such a push by default is refused if the working
@@ -400,8 +400,8 @@ when the tip of the current branch is updated to the new commit, and
 exit with a zero status.
 
 For example, the hook can simply run `git read-tree -u -m HEAD "$1"`
-in order to emulate 'git fetch' that is run in the reverse direction
-with `git push`, as the two-tree form of `read-tree -u -m` is
+in order to emulate `git fetch` that is run in the reverse direction
+with `git push`, as the two-tree form of `git read-tree -u -m` is
 essentially the same as `git checkout` that switches branches while
 keeping the local changes in the working tree that do not interfere
 with the difference between the branches.
@@ -410,15 +410,16 @@ with the difference between the branches.
 pre-auto-gc
 ~~~~~~~~~~~
 
-This hook is invoked by 'git gc --auto'. It takes no parameter, and
-exiting with non-zero status from this script causes the 'git gc --auto'
-to abort.
+This hook is invoked by `git gc --auto` (see linkgit:git-gc[1]). It
+takes no parameter, and exiting with non-zero status from this script
+causes the `git gc --auto` to abort.
 
 post-rewrite
 ~~~~~~~~~~~~
 
-This hook is invoked by commands that rewrite commits (`git commit
---amend`, 'git-rebase'; currently 'git-filter-branch' does 'not' call
+This hook is invoked by commands that rewrite commits
+(linkgit:git-commit[1] when called with `--amend` and
+linkgit:git-rebase[1]; currently `git filter-branch` does 'not' call
 it!).  Its first argument denotes the command it was invoked by:
 currently one of `amend` or `rebase`.  Further command-dependent
 arguments may be passed in the future.
@@ -450,16 +451,16 @@ processed by rebase.
 sendemail-validate
 ~~~~~~~~~~~~~~~~~~
 
-This hook is invoked by 'git send-email'.  It takes a single parameter,
+This hook is invoked by linkgit:git-send-email[1].  It takes a single parameter,
 the name of the file that holds the e-mail to be sent.  Exiting with a
-non-zero status causes 'git send-email' to abort before sending any
+non-zero status causes `git send-email` to abort before sending any
 e-mails.
 
 fsmonitor-watchman
 ~~~~~~~~~~~~~~~~~~
 
-This hook is invoked when the configuration option core.fsmonitor is
-set to .git/hooks/fsmonitor-watchman.  It takes two arguments, a version
+This hook is invoked when the configuration option `core.fsmonitor` is
+set to `.git/hooks/fsmonitor-watchman`.  It takes two arguments, a version
 (currently 1) and the time in elapsed nanoseconds since midnight,
 January 1, 1970.
 
@@ -478,7 +479,7 @@ directories are checked for untracked files based on the path names
 given.
 
 An optimized way to tell git "all files have changed" is to return
-the filename '/'.
+the filename `/`.
 
 The exit status determines whether git will use the data from the
 hook to limit its search.  On error, it will fall back to verifying
index 12b6bbf..662c271 100644 (file)
@@ -35,7 +35,13 @@ include::fmt-merge-msg-config.txt[]
 merge.renameLimit::
        The number of files to consider when performing rename detection
        during a merge; if not specified, defaults to the value of
-       diff.renameLimit.
+       diff.renameLimit. This setting has no effect if rename detection
+       is turned off.
+
+merge.renames::
+       Whether and how Git detects renames.  If set to "false",
+       rename detection is disabled. If set to "true", basic rename
+       detection is enabled.  Defaults to the value of diff.renames.
 
 merge.renormalize::
        Tell Git that canonical representation of files in the
index 4a58aad..aa66cbe 100644 (file)
@@ -23,8 +23,9 @@ recursive::
        causing mismerges by tests done on actual merge commits
        taken from Linux 2.6 kernel development history.
        Additionally this can detect and handle merges involving
-       renames.  This is the default merge strategy when
-       pulling or merging one branch.
+       renames, but currently cannot make use of detected
+       copies.  This is the default merge strategy when pulling
+       or merging one branch.
 +
 The 'recursive' strategy can take the following options:
 
@@ -84,12 +85,14 @@ no-renormalize;;
        `merge.renormalize` configuration variable.
 
 no-renames;;
-       Turn off rename detection.
+       Turn off rename detection. This overrides the `merge.renames`
+       configuration variable.
        See also linkgit:git-diff[1] `--no-renames`.
 
 find-renames[=<n>];;
        Turn on rename detection, optionally setting the similarity
-       threshold.  This is the default.
+       threshold.  This is the default. This overrides the
+       'merge.renames' configuration variable.
        See also linkgit:git-diff[1] `--find-renames`.
 
 rename-threshold=<n>;;
index dfcc49c..7d1bd44 100644 (file)
@@ -7,6 +7,10 @@ syntax.  Here are various ways to spell object names.  The
 ones listed near the end of this list name trees and
 blobs contained in a commit.
 
+NOTE: This document shows the "raw" syntax as seen by git. The shell
+and other UIs might require additional quoting to protect special
+characters and to avoid word splitting.
+
 '<sha1>', e.g. 'dae86e1950b1277e545cee180551750029cfe735', 'dae86e'::
   The full SHA-1 object name (40-byte hexadecimal string), or
   a leading substring that is unique within the repository.
@@ -186,6 +190,8 @@ existing tag object.
   is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a
   literal '!' character, followed by 'foo'. Any other sequence beginning with
   ':/!' is reserved for now.
+  Depending on the given text, the shell's word splitting rules might
+  require additional quoting.
 
 '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::
   A suffix ':' followed by a path names the blob or tree
@@ -345,6 +351,7 @@ Here are a handful of examples using the Loeliger illustration above,
 with each step in the notation's expansion and selection carefully
 spelt out:
 
+....
    Args   Expanded arguments    Selected commits
    D                            G H D
    D F                          G H I J D F
@@ -367,3 +374,4 @@ spelt out:
          = B ^B^1 ^B^2 ^B^3
          = B ^D ^E ^F          B
    F^! D  = F ^I ^J D           G H D F
+....
index 9a778b0..fa39ac9 100644 (file)
@@ -47,21 +47,23 @@ will first feed the user-wide one to the callback, and then the
 repo-specific one; by overwriting, the higher-priority repo-specific
 value is left at the end).
 
-The `git_config_with_options` function lets the caller examine config
+The `config_with_options` function lets the caller examine config
 while adjusting some of the default behavior of `git_config`. It should
 almost never be used by "regular" Git code that is looking up
 configuration variables. It is intended for advanced callers like
 `git-config`, which are intentionally tweaking the normal config-lookup
 process. It takes two extra parameters:
 
-`filename`::
-If this parameter is non-NULL, it specifies the name of a file to
-parse for configuration, rather than looking in the usual files. Regular
-`git_config` defaults to `NULL`.
+`config_source`::
+If this parameter is non-NULL, it specifies the source to parse for
+configuration, rather than looking in the usual files. See `struct
+git_config_source` in `config.h` for details. Regular `git_config` defaults
+to `NULL`.
 
-`respect_includes`::
-Specify whether include directives should be followed in parsed files.
-Regular `git_config` defaults to `1`.
+`opts`::
+Specify options to adjust the behavior of parsing config files. See `struct
+config_options` in `config.h` for details. As an example: regular `git_config`
+sets `opts.respect_includes` to `1` by default.
 
 Reading Specific Files
 ----------------------
index b0c11f8..9febfb1 100644 (file)
@@ -35,13 +35,18 @@ Functions
        Free all memory associated with the array and return it to the
        initial, empty state.
 
+`oid_array_for_each`::
+       Iterate over each element of the list, executing the callback
+       function for each one. Does not sort the list, so any custom
+       hash order is retained. If the callback returns a non-zero
+       value, the iteration ends immediately and the callback's
+       return is propagated; otherwise, 0 is returned.
+
 `oid_array_for_each_unique`::
-       Efficiently iterate over each unique element of the list,
-       executing the callback function for each one. If the array is
-       not sorted, this function has the side effect of sorting it. If
-       the callback returns a non-zero value, the iteration ends
-       immediately and the callback's return is propagated; otherwise,
-       0 is returned.
+       Iterate over each unique element of the list in sorted order,
+       but otherwise behave like `oid_array_for_each`. If the array
+       is not sorted, this function has the side effect of sorting
+       it.
 
 Examples
 --------
index 8e5bf60..70a99fd 100644 (file)
@@ -36,6 +36,98 @@ Git pack format
 
   - The trailer records 20-byte SHA-1 checksum of all of the above.
 
+=== Object types
+
+Valid object types are:
+
+- OBJ_COMMIT (1)
+- OBJ_TREE (2)
+- OBJ_BLOB (3)
+- OBJ_TAG (4)
+- OBJ_OFS_DELTA (6)
+- OBJ_REF_DELTA (7)
+
+Type 5 is reserved for future expansion. Type 0 is invalid.
+
+=== Deltified representation
+
+Conceptually there are only four object types: commit, tree, tag and
+blob. However to save space, an object could be stored as a "delta" of
+another "base" object. These representations are assigned new types
+ofs-delta and ref-delta, which is only valid in a pack file.
+
+Both ofs-delta and ref-delta store the "delta" to be applied to
+another object (called 'base object') to reconstruct the object. The
+difference between them is, ref-delta directly encodes 20-byte base
+object name. If the base object is in the same pack, ofs-delta encodes
+the offset of the base object in the pack instead.
+
+The base object could also be deltified if it's in the same pack.
+Ref-delta can also refer to an object outside the pack (i.e. the
+so-called "thin pack"). When stored on disk however, the pack should
+be self contained to avoid cyclic dependency.
+
+The delta data is a sequence of instructions to reconstruct an object
+from the base object. If the base object is deltified, it must be
+converted to canonical form first. Each instruction appends more and
+more data to the target object until it's complete. There are two
+supported instructions so far: one for copy a byte range from the
+source object and one for inserting new data embedded in the
+instruction itself.
+
+Each instruction has variable length. Instruction type is determined
+by the seventh bit of the first octet. The following diagrams follow
+the convention in RFC 1951 (Deflate compressed data format).
+
+==== Instruction to copy from base object
+
+  +----------+---------+---------+---------+---------+-------+-------+-------+
+  | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |
+  +----------+---------+---------+---------+---------+-------+-------+-------+
+
+This is the instruction format to copy a byte range from the source
+object. It encodes the offset to copy from and the number of bytes to
+copy. Offset and size are in little-endian order.
+
+All offset and size bytes are optional. This is to reduce the
+instruction size when encoding small offsets or sizes. The first seven
+bits in the first octet determines which of the next seven octets is
+present. If bit zero is set, offset1 is present. If bit one is set
+offset2 is present and so on.
+
+Note that a more compact instruction does not change offset and size
+encoding. For example, if only offset2 is omitted like below, offset3
+still contains bits 16-23. It does not become offset2 and contains
+bits 8-15 even if it's right next to offset1.
+
+  +----------+---------+---------+
+  | 10000101 | offset1 | offset3 |
+  +----------+---------+---------+
+
+In its most compact form, this instruction only takes up one byte
+(0x80) with both offset and size omitted, which will have default
+values zero. There is another exception: size zero is automatically
+converted to 0x10000.
+
+==== Instruction to add new data
+
+  +----------+============+
+  | 0xxxxxxx |    data    |
+  +----------+============+
+
+This is the instruction to construct target object without the base
+object. The following data is appended to the target object. The first
+seven bits of the first octet determines the size of data in
+bytes. The size must be non-zero.
+
+==== Reserved instruction
+
+  +----------+============
+  | 00000000 |
+  +----------+============
+
+This is the instruction reserved for future expansion.
+
 == Original (version 1) pack-*.idx files have the following format:
 
   - The header consists of 256 4-byte network byte order
index 136179d..49bda76 100644 (file)
@@ -290,6 +290,15 @@ included in the clients request as well as the potential addition of the
        Cannot be used with "deepen", but can be used with
        "deepen-since".
 
+If the 'filter' feature is advertised, the following argument can be
+included in the client's request:
+
+    filter <filter-spec>
+       Request that various objects from the packfile be omitted
+       using one of several filtering techniques. These are intended
+       for use with partial clone and partial fetch operations. See
+       `rev-list` for possible "filter-spec" values.
+
 The response of `fetch` is broken into a number of sections separated by
 delimiter packets (0001), with each section beginning with its section
 header.
@@ -393,3 +402,13 @@ header.
                1 - pack data
                2 - progress messages
                3 - fatal error message just before stream aborts
+
+ server-option
+~~~~~~~~~~~~~~~
+
+If advertised, indicates that any number of server specific options can be
+included in a request.  This is done by sending each option as a
+"server-option=<option>" capability line in the capability-list section of
+a request.
+
+The provided options must not contain a NUL or LF character.
index 5183b15..01dedfe 100644 (file)
@@ -8,20 +8,22 @@ repo, and therefore grafts are introduced pretending that
 these commits have no parents.
 *********************************************************
 
-The basic idea is to write the SHA-1s of shallow commits into
-$GIT_DIR/shallow, and handle its contents like the contents
-of $GIT_DIR/info/grafts (with the difference that shallow
-cannot contain parent information).
-
-This information is stored in a new file instead of grafts, or
-even the config, since the user should not touch that file
-at all (even throughout development of the shallow clone, it
-was never manually edited!).
+$GIT_DIR/shallow lists commit object names and tells Git to
+pretend as if they are root commits (e.g. "git log" traversal
+stops after showing them; "git fsck" does not complain saying
+the commits listed on their "parent" lines do not exist).
 
 Each line contains exactly one SHA-1. When read, a commit_graft
 will be constructed, which has nr_parent < 0 to make it easier
 to discern from user provided grafts.
 
+Note that the shallow feature could not be changed easily to
+use replace refs: a commit containing a `mergetag` is not allowed
+to be replaced, not even by a root commit. Such a commit can be
+made shallow, though. Also, having a `shallow` file explicitly
+listing all the commits made shallow makes it a *lot* easier to
+do shallow-specific things such as to deepen the history.
+
 Since fsck-objects relies on the library to read the objects,
 it honours shallow commits automatically.
 
index ad880d1..4bca653 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
 LIB_OBJS += refs/iterator.o
 LIB_OBJS += refs/packed-backend.o
 LIB_OBJS += refs/ref-cache.o
+LIB_OBJS += refspec.o
 LIB_OBJS += ref-filter.o
 LIB_OBJS += remote.o
 LIB_OBJS += replace-object.o
index 89fda1d..370a56d 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -20,6 +20,7 @@ int advice_rm_hints = 1;
 int advice_add_embedded_repo = 1;
 int advice_ignored_hook = 1;
 int advice_waiting_for_editor = 1;
+int advice_graft_file_deprecated = 1;
 
 static int advice_use_color = -1;
 static char advice_colors[][COLOR_MAXLEN] = {
@@ -70,6 +71,7 @@ static struct {
        { "addembeddedrepo", &advice_add_embedded_repo },
        { "ignoredhook", &advice_ignored_hook },
        { "waitingforeditor", &advice_waiting_for_editor },
+       { "graftfiledeprecated", &advice_graft_file_deprecated },
 
        /* make this an alias for backward compatibility */
        { "pushnonfastforward", &advice_push_update_rejected }
index 70568fa..9f5064e 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -21,6 +21,7 @@ extern int advice_rm_hints;
 extern int advice_add_embedded_repo;
 extern int advice_ignored_hook;
 extern int advice_waiting_for_editor;
+extern int advice_graft_file_deprecated;
 
 int git_default_advice_config(const char *var, const char *value);
 __attribute__((format (printf, 1, 2)))
diff --git a/apply.c b/apply.c
index 7e5792c..d79e615 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -2375,7 +2375,7 @@ static void update_pre_post_images(struct image *preimage,
        if (postlen
            ? postlen < new_buf - postimage->buf
            : postimage->len < new_buf - postimage->buf)
-               die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
+               BUG("caller miscounted postlen: asked %d, orig = %d, used = %d",
                    (int)postlen, (int) postimage->len, (int)(new_buf - postimage->buf));
 
        /* Fix the length of the whole thing */
@@ -3509,7 +3509,7 @@ static int load_current(struct apply_state *state,
        unsigned mode = patch->new_mode;
 
        if (!patch->is_new)
-               die("BUG: patch to %s is not a creation", patch->old_name);
+               BUG("patch to %s is not a creation", patch->old_name);
 
        pos = cache_name_pos(name, strlen(name));
        if (pos < 0)
@@ -3860,9 +3860,9 @@ static int check_unsafe_path(struct patch *patch)
        if (!patch->is_delete)
                new_name = patch->new_name;
 
-       if (old_name && !verify_path(old_name))
+       if (old_name && !verify_path(old_name, patch->old_mode))
                return error(_("invalid path '%s'"), old_name);
-       if (new_name && !verify_path(new_name))
+       if (new_name && !verify_path(new_name, patch->new_mode))
                return error(_("invalid path '%s'"), new_name);
        return 0;
 }
@@ -4058,7 +4058,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
 {
        struct patch *patch;
        struct index_state result = { NULL };
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        int res;
 
        /* Once we start supporting the reverse patch, it may be
index 3563bcb..b6f58dd 100644 (file)
@@ -276,7 +276,7 @@ static int write_tar_entry(struct archiver_args *args,
                memcpy(header.name, path, pathlen);
 
        if (S_ISREG(mode) && !args->convert &&
-           oid_object_info(oid, &size) == OBJ_BLOB &&
+           oid_object_info(the_repository, oid, &size) == OBJ_BLOB &&
            size > big_file_threshold)
                buffer = NULL;
        else if (S_ISLNK(mode) || S_ISREG(mode)) {
@@ -441,7 +441,7 @@ static int write_tar_filter_archive(const struct archiver *ar,
        int r;
 
        if (!ar->data)
-               die("BUG: tar-filter archiver called with no filter defined");
+               BUG("tar-filter archiver called with no filter defined");
 
        strbuf_addstr(&cmd, ar->data);
        if (args->compression_level >= 0)
index 6b20bce..74f3fe9 100644 (file)
@@ -325,7 +325,8 @@ static int write_zip_entry(struct archiver_args *args,
                compressed_size = 0;
                buffer = NULL;
        } else if (S_ISREG(mode) || S_ISLNK(mode)) {
-               enum object_type type = oid_object_info(oid, &size);
+               enum object_type type = oid_object_info(the_repository, oid,
+                                                       &size);
 
                method = 0;
                attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
index 5d370fa..cb5bcd2 100644 (file)
@@ -64,6 +64,26 @@ void argv_array_pop(struct argv_array *array)
        array->argc--;
 }
 
+void argv_array_split(struct argv_array *array, const char *to_split)
+{
+       while (isspace(*to_split))
+               to_split++;
+       for (;;) {
+               const char *p = to_split;
+
+               if (!*p)
+                       break;
+
+               while (*p && !isspace(*p))
+                       p++;
+               argv_array_push_nodup(array, xstrndup(to_split, p - to_split));
+
+               while (isspace(*p))
+                       p++;
+               to_split = p;
+       }
+}
+
 void argv_array_clear(struct argv_array *array)
 {
        if (array->argv != empty_argv) {
index 29056e4..750c30d 100644 (file)
@@ -19,6 +19,8 @@ LAST_ARG_MUST_BE_NULL
 void argv_array_pushl(struct argv_array *, ...);
 void argv_array_pushv(struct argv_array *, const char **);
 void argv_array_pop(struct argv_array *);
+/* Splits by whitespace; does not handle quoted arguments! */
+void argv_array_split(struct argv_array *, const char *);
 void argv_array_clear(struct argv_array *);
 const char **argv_array_detach(struct argv_array *);
 
diff --git a/attr.c b/attr.c
index 03a678f..067fb9e 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -157,7 +157,7 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
 
        size = hashmap_get_size(&map->map);
        if (size < check->all_attrs_nr)
-               die("BUG: interned attributes shouldn't be deleted");
+               BUG("interned attributes shouldn't be deleted");
 
        /*
         * If the number of attributes in the global dictionary has increased
@@ -541,7 +541,7 @@ static void check_vector_remove(struct attr_check *check)
                        break;
 
        if (i >= check_vector.nr)
-               die("BUG: no entry found");
+               BUG("no entry found");
 
        /* shift entries over */
        for (; i < check_vector.nr - 1; i++)
@@ -599,11 +599,11 @@ struct attr_check *attr_check_initl(const char *one, ...)
                const struct git_attr *attr;
                param = va_arg(params, const char *);
                if (!param)
-                       die("BUG: counted %d != ended at %d",
+                       BUG("counted %d != ended at %d",
                            check->nr, cnt);
                attr = git_attr(param);
                if (!attr)
-                       die("BUG: %s: not a valid attribute name", param);
+                       BUG("%s: not a valid attribute name", param);
                check->items[cnt].attr = attr;
        }
        va_end(params);
@@ -714,7 +714,7 @@ void git_attr_set_direction(enum git_attr_direction new_direction,
                            struct index_state *istate)
 {
        if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
-               die("BUG: non-INDEX attr direction in a bare repo");
+               BUG("non-INDEX attr direction in a bare repo");
 
        if (new_direction != direction)
                drop_all_attr_stacks();
diff --git a/blame.c b/blame.c
index 78c9808..14d0e0b 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -81,7 +81,7 @@ static void verify_working_tree_path(struct commit *work_tree, const char *path)
                unsigned mode;
 
                if (!get_tree_entry(commit_oid, path, &blob_oid, &mode) &&
-                   oid_object_info(&blob_oid, NULL) == OBJ_BLOB)
+                   oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
                        return;
        }
 
@@ -504,7 +504,7 @@ static int fill_blob_sha1_and_mode(struct blame_origin *origin)
                return 0;
        if (get_tree_entry(&origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
                goto error_out;
-       if (oid_object_info(&origin->blob_oid, NULL) != OBJ_BLOB)
+       if (oid_object_info(the_repository, &origin->blob_oid, NULL) != OBJ_BLOB)
                goto error_out;
        return 0;
  error_out:
@@ -551,10 +551,10 @@ static struct blame_origin *find_origin(struct commit *parent,
        diff_setup_done(&diff_opts);
 
        if (is_null_oid(&origin->commit->object.oid))
-               do_diff_cache(&parent->tree->object.oid, &diff_opts);
+               do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
        else
-               diff_tree_oid(&parent->tree->object.oid,
-                             &origin->commit->tree->object.oid,
+               diff_tree_oid(get_commit_tree_oid(parent),
+                             get_commit_tree_oid(origin->commit),
                              "", &diff_opts);
        diffcore_std(&diff_opts);
 
@@ -620,10 +620,10 @@ static struct blame_origin *find_rename(struct commit *parent,
        diff_setup_done(&diff_opts);
 
        if (is_null_oid(&origin->commit->object.oid))
-               do_diff_cache(&parent->tree->object.oid, &diff_opts);
+               do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
        else
-               diff_tree_oid(&parent->tree->object.oid,
-                             &origin->commit->tree->object.oid,
+               diff_tree_oid(get_commit_tree_oid(parent),
+                             get_commit_tree_oid(origin->commit),
                              "", &diff_opts);
        diffcore_std(&diff_opts);
 
@@ -1255,10 +1255,10 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                diff_opts.flags.find_copies_harder = 1;
 
        if (is_null_oid(&target->commit->object.oid))
-               do_diff_cache(&parent->tree->object.oid, &diff_opts);
+               do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
        else
-               diff_tree_oid(&parent->tree->object.oid,
-                             &target->commit->tree->object.oid,
+               diff_tree_oid(get_commit_tree_oid(parent),
+                             get_commit_tree_oid(target->commit),
                              "", &diff_opts);
 
        if (!diff_opts.flags.find_copies_harder)
@@ -1806,7 +1806,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
                        l->item = c;
                        if (add_decoration(&sb->revs->children,
                                           &c->parents->item->object, l))
-                               die("BUG: not unique item in first-parent chain");
+                               BUG("not unique item in first-parent chain");
                        c = c->parents->item;
                }
 
index 2672054..f967c98 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -3,12 +3,13 @@
 #include "config.h"
 #include "branch.h"
 #include "refs.h"
+#include "refspec.h"
 #include "remote.h"
 #include "commit.h"
 #include "worktree.h"
 
 struct tracking {
-       struct refspec spec;
+       struct refspec_item spec;
        char *src;
        const char *remote;
        int matches;
@@ -218,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)
 static int check_tracking_branch(struct remote *remote, void *cb_data)
 {
        char *tracking_branch = cb_data;
-       struct refspec query;
-       memset(&query, 0, sizeof(struct refspec));
+       struct refspec_item query;
+       memset(&query, 0, sizeof(struct refspec_item));
        query.dst = tracking_branch;
        return !remote_find_tracking(remote, &query);
 }
index c9e2619..8a155dd 100644 (file)
@@ -265,8 +265,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
-static struct lock_file lock_file;
-
 static const char ignore_error[] =
 N_("The following paths are ignored by one of your .gitignore files:\n");
 
@@ -393,6 +391,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        int add_new_files;
        int require_pathspec;
        char *seen = NULL;
+       struct lock_file lock_file = LOCK_INIT;
 
        git_config(add_config, NULL);
 
index d834f9e..aa989e7 100644 (file)
@@ -403,11 +403,11 @@ static void am_load(struct am_state *state)
        struct strbuf sb = STRBUF_INIT;
 
        if (read_state_file(&sb, state, "next", 1) < 0)
-               die("BUG: state file 'next' does not exist");
+               BUG("state file 'next' does not exist");
        state->cur = strtol(sb.buf, NULL, 10);
 
        if (read_state_file(&sb, state, "last", 1) < 0)
-               die("BUG: state file 'last' does not exist");
+               BUG("state file 'last' does not exist");
        state->last = strtol(sb.buf, NULL, 10);
 
        if (read_author_script(state) < 0)
@@ -986,7 +986,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
        case PATCH_FORMAT_MBOXRD:
                return split_mail_mbox(state, paths, keep_cr, 1);
        default:
-               die("BUG: invalid patch_format");
+               BUG("invalid patch_format");
        }
        return -1;
 }
@@ -1041,7 +1041,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
                str = "b";
                break;
        default:
-               die("BUG: invalid value for state->keep");
+               BUG("invalid value for state->keep");
        }
 
        write_state_text(state, "keep", str);
@@ -1058,7 +1058,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
                str = "t";
                break;
        default:
-               die("BUG: invalid value for state->scissors");
+               BUG("invalid value for state->scissors");
        }
        write_state_text(state, "scissors", str);
 
@@ -1216,7 +1216,7 @@ static int parse_mail(struct am_state *state, const char *mail)
                mi.keep_non_patch_brackets_in_subject = 1;
                break;
        default:
-               die("BUG: invalid value for state->keep");
+               BUG("invalid value for state->keep");
        }
 
        if (state->message_id)
@@ -1232,7 +1232,7 @@ static int parse_mail(struct am_state *state, const char *mail)
                mi.use_scissors = 1;
                break;
        default:
-               die("BUG: invalid value for state->scissors");
+               BUG("invalid value for state->scissors");
        }
 
        mi.input = xfopen(mail, "r");
@@ -1463,7 +1463,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
        int options = 0;
 
        if (init_apply_state(&apply_state, NULL))
-               die("BUG: init_apply_state() failed");
+               BUG("init_apply_state() failed");
 
        argv_array_push(&apply_opts, "apply");
        argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
@@ -1489,7 +1489,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
                apply_state.apply_verbosity = verbosity_silent;
 
        if (check_apply_state(&apply_state, force_apply))
-               die("BUG: check_apply_state() failed");
+               BUG("check_apply_state() failed");
 
        argv_array_push(&apply_paths, am_path(state, "patch"));
 
@@ -1542,7 +1542,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
        char *their_tree_name;
 
        if (get_oid("HEAD", &our_tree) < 0)
-               hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&our_tree, the_hash_algo->empty_tree);
 
        if (build_fake_ancestor(state, index_path))
                return error("could not build fake ancestor");
@@ -2042,7 +2042,7 @@ static void am_skip(struct am_state *state)
        am_rerere_clear();
 
        if (get_oid("HEAD", &head))
-               hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&head, the_hash_algo->empty_tree);
 
        if (clean_index(&head, &head))
                die(_("failed to clean index"));
@@ -2105,11 +2105,11 @@ static void am_abort(struct am_state *state)
        curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
        has_curr_head = curr_branch && !is_null_oid(&curr_head);
        if (!has_curr_head)
-               hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&curr_head, the_hash_algo->empty_tree);
 
        has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
        if (!has_orig_head)
-               hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&orig_head, the_hash_algo->empty_tree);
 
        clean_index(&curr_head, &orig_head);
 
@@ -2407,7 +2407,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                ret = show_patch(&state);
                break;
        default:
-               die("BUG: invalid resume value");
+               BUG("invalid resume value");
        }
 
        am_state_release(&state);
index db38c0b..4202584 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "cache.h"
 #include "config.h"
+#include "color.h"
 #include "builtin.h"
 #include "commit.h"
 #include "diff.h"
@@ -23,6 +24,7 @@
 #include "dir.h"
 #include "progress.h"
 #include "blame.h"
+#include "string-list.h"
 
 static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
 
@@ -46,6 +48,8 @@ static int xdl_opts;
 static int abbrev = -1;
 static int no_whole_file_rename;
 static int show_progress;
+static char repeated_meta_color[COLOR_MAXLEN];
+static int coloring_mode;
 
 static struct date_mode blame_date_mode = { DATE_ISO8601 };
 static size_t blame_date_width;
@@ -316,10 +320,12 @@ static const char *format_time(timestamp_t time, const char *tz_str,
 #define OUTPUT_PORCELAIN       010
 #define OUTPUT_SHOW_NAME       020
 #define OUTPUT_SHOW_NUMBER     040
-#define OUTPUT_SHOW_SCORE      0100
-#define OUTPUT_NO_AUTHOR       0200
+#define OUTPUT_SHOW_SCORE      0100
+#define OUTPUT_NO_AUTHOR       0200
 #define OUTPUT_SHOW_EMAIL      0400
-#define OUTPUT_LINE_PORCELAIN 01000
+#define OUTPUT_LINE_PORCELAIN  01000
+#define OUTPUT_COLOR_LINE      02000
+#define OUTPUT_SHOW_AGE_WITH_COLOR     04000
 
 static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
 {
@@ -367,6 +373,63 @@ static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
                putchar('\n');
 }
 
+static struct color_field {
+       timestamp_t hop;
+       char col[COLOR_MAXLEN];
+} *colorfield;
+static int colorfield_nr, colorfield_alloc;
+
+static void parse_color_fields(const char *s)
+{
+       struct string_list l = STRING_LIST_INIT_DUP;
+       struct string_list_item *item;
+       enum { EXPECT_DATE, EXPECT_COLOR } next = EXPECT_COLOR;
+
+       colorfield_nr = 0;
+
+       /* Ideally this would be stripped and split at the same time? */
+       string_list_split(&l, s, ',', -1);
+       ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
+
+       for_each_string_list_item(item, &l) {
+               switch (next) {
+               case EXPECT_DATE:
+                       colorfield[colorfield_nr].hop = approxidate(item->string);
+                       next = EXPECT_COLOR;
+                       colorfield_nr++;
+                       ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
+                       break;
+               case EXPECT_COLOR:
+                       if (color_parse(item->string, colorfield[colorfield_nr].col))
+                               die(_("expecting a color: %s"), item->string);
+                       next = EXPECT_DATE;
+                       break;
+               }
+       }
+
+       if (next == EXPECT_COLOR)
+               die (_("must end with a color"));
+
+       colorfield[colorfield_nr].hop = TIME_MAX;
+}
+
+static void setup_default_color_by_age(void)
+{
+       parse_color_fields("blue,12 month ago,white,1 month ago,red");
+}
+
+static void determine_line_heat(struct blame_entry *ent, const char **dest_color)
+{
+       int i = 0;
+       struct commit_info ci;
+       get_commit_info(ent->suspect->commit, &ci, 1);
+
+       while (i < colorfield_nr && ci.author_time > colorfield[i].hop)
+               i++;
+
+       *dest_color = colorfield[i].col;
+}
+
 static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
 {
        int cnt;
@@ -375,15 +438,35 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
        struct commit_info ci;
        char hex[GIT_MAX_HEXSZ + 1];
        int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
+       const char *default_color = NULL, *color = NULL, *reset = NULL;
 
        get_commit_info(suspect->commit, &ci, 1);
        oid_to_hex_r(hex, &suspect->commit->object.oid);
 
        cp = blame_nth_line(sb, ent->lno);
+
+       if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
+               determine_line_heat(ent, &default_color);
+               color = default_color;
+               reset = GIT_COLOR_RESET;
+       }
+
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
                char ch;
                int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
 
+               if (opt & OUTPUT_COLOR_LINE) {
+                       if (cnt > 0) {
+                               color = repeated_meta_color;
+                               reset = GIT_COLOR_RESET;
+                       } else  {
+                               color = default_color ? default_color : NULL;
+                               reset = default_color ? GIT_COLOR_RESET : NULL;
+                       }
+               }
+               if (color)
+                       fputs(color, stdout);
+
                if (suspect->commit->object.flags & UNINTERESTING) {
                        if (blank_boundary)
                                memset(hex, ' ', length);
@@ -433,6 +516,8 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
                        printf(" %*d) ",
                               max_digits, ent->lno + 1 + cnt);
                }
+               if (reset)
+                       fputs(reset, stdout);
                do {
                        ch = *cp++;
                        putchar(ch);
@@ -607,6 +692,30 @@ static int git_blame_config(const char *var, const char *value, void *cb)
                parse_date_format(value, &blame_date_mode);
                return 0;
        }
+       if (!strcmp(var, "color.blame.repeatedlines")) {
+               if (color_parse_mem(value, strlen(value), repeated_meta_color))
+                       warning(_("invalid color '%s' in color.blame.repeatedLines"),
+                               value);
+               return 0;
+       }
+       if (!strcmp(var, "color.blame.highlightrecent")) {
+               parse_color_fields(value);
+               return 0;
+       }
+
+       if (!strcmp(var, "blame.coloring")) {
+               if (!strcmp(value, "repeatedLines")) {
+                       coloring_mode |= OUTPUT_COLOR_LINE;
+               } else if (!strcmp(value, "highlightRecent")) {
+                       coloring_mode |= OUTPUT_SHOW_AGE_WITH_COLOR;
+               } else if (!strcmp(value, "none")) {
+                       coloring_mode &= ~(OUTPUT_COLOR_LINE |
+                                           OUTPUT_SHOW_AGE_WITH_COLOR);
+               } else {
+                       warning(_("invalid value for blame.coloring"));
+                       return 0;
+               }
+       }
 
        if (git_diff_heuristic_config(var, value, cb) < 0)
                return -1;
@@ -655,7 +764,7 @@ static int is_a_rev(const char *name)
 
        if (get_oid(name, &oid))
                return 0;
-       return OBJ_NONE < oid_object_info(&oid, NULL);
+       return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
 }
 
 int cmd_blame(int argc, const char **argv, const char *prefix)
@@ -690,6 +799,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
                OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
                OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+               OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
+               OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
 
                /*
                 * The following two options are parsed by parse_revision_opt()
@@ -714,6 +825,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        unsigned int range_i;
        long anchor;
 
+       setup_default_color_by_age();
        git_config(git_blame_config, &output_option);
        init_revisions(&revs, NULL);
        revs.date_mode = blame_date_mode;
@@ -949,8 +1061,17 @@ parse_done:
 
        blame_coalesce(&sb);
 
-       if (!(output_option & OUTPUT_PORCELAIN))
+       if (!(output_option & (OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR)))
+               output_option |= coloring_mode;
+
+       if (!(output_option & OUTPUT_PORCELAIN)) {
                find_alignment(&sb, &output_option);
+               if (!*repeated_meta_color &&
+                   (output_option & OUTPUT_COLOR_LINE))
+                       strcpy(repeated_meta_color, GIT_COLOR_CYAN);
+       }
+       if (output_option & OUTPUT_ANNOTATE_COMPAT)
+               output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
 
        output(&sb, output_option);
        free((void *)sb.final_buf);
index efc9ac1..5bb5123 100644 (file)
@@ -500,7 +500,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 
        if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
            !skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
-               die("BUG: expected prefix missing for refs");
+               BUG("expected prefix missing for refs");
        }
 
        if (copy)
index 2c46d25..665b581 100644 (file)
@@ -77,7 +77,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
        switch (opt) {
        case 't':
                oi.type_name = &sb;
-               if (oid_object_info_extended(&oid, &oi, flags) < 0)
+               if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
                        die("git cat-file: could not get object info");
                if (sb.len) {
                        printf("%s\n", sb.buf);
@@ -88,7 +88,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 
        case 's':
                oi.sizep = &size;
-               if (oid_object_info_extended(&oid, &oi, flags) < 0)
+               if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
                        die("git cat-file: could not get object info");
                printf("%lu\n", size);
                return 0;
@@ -116,7 +116,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                /* else fallthrough */
 
        case 'p':
-               type = oid_object_info(&oid, NULL);
+               type = oid_object_info(the_repository, &oid, NULL);
                if (type < 0)
                        die("Not a valid object name %s", obj_name);
 
@@ -140,7 +140,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
        case 0:
                if (type_from_string(exp_type) == OBJ_BLOB) {
                        struct object_id blob_oid;
-                       if (oid_object_info(&oid, NULL) == OBJ_TAG) {
+                       if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
                                char *buffer = read_object_file(&oid, &type,
                                                                &size);
                                const char *target;
@@ -151,7 +151,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        } else
                                oidcpy(&blob_oid, &oid);
 
-                       if (oid_object_info(&blob_oid, NULL) == OBJ_BLOB)
+                       if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
                                return stream_blob_to_fd(1, &blob_oid, NULL, 0);
                        /*
                         * we attempted to dereference a tag to a blob
@@ -312,7 +312,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
                                        die("could not convert '%s' %s",
                                            oid_to_hex(oid), data->rest);
                        } else
-                               die("BUG: invalid cmdmode: %c", opt->cmdmode);
+                               BUG("invalid cmdmode: %c", opt->cmdmode);
                        batch_write(opt, contents, size);
                        free(contents);
                } else if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
@@ -342,7 +342,7 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
        struct strbuf buf = STRBUF_INIT;
 
        if (!data->skip_object_info &&
-           oid_object_info_extended(&data->oid, &data->info,
+           oid_object_info_extended(the_repository, &data->oid, &data->info,
                                     OBJECT_INFO_LOOKUP_REPLACE) < 0) {
                printf("%s missing\n",
                       obj_name ? obj_name : oid_to_hex(&data->oid));
@@ -387,7 +387,7 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
                               (uintmax_t)strlen(obj_name), obj_name);
                        break;
                default:
-                       die("BUG: unknown get_sha1_with_context result %d\n",
+                       BUG("unknown get_sha1_with_context result %d\n",
                               result);
                        break;
                }
index b49b582..2b3b768 100644 (file)
@@ -484,7 +484,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
 
        resolve_undo_clear();
        if (opts->force) {
-               ret = reset_tree(new_branch_info->commit->tree, opts, 1, writeout_error);
+               ret = reset_tree(get_commit_tree(new_branch_info->commit),
+                                opts, 1, writeout_error);
                if (ret)
                        return ret;
        } else {
@@ -570,18 +571,23 @@ static int merge_working_tree(const struct checkout_opts *opts,
                        o.verbosity = 0;
                        work = write_tree_from_memory(&o);
 
-                       ret = reset_tree(new_branch_info->commit->tree, opts, 1,
+                       ret = reset_tree(get_commit_tree(new_branch_info->commit),
+                                        opts, 1,
                                         writeout_error);
                        if (ret)
                                return ret;
                        o.ancestor = old_branch_info->name;
                        o.branch1 = new_branch_info->name;
                        o.branch2 = "local";
-                       ret = merge_trees(&o, new_branch_info->commit->tree, work,
-                               old_branch_info->commit->tree, &result);
+                       ret = merge_trees(&o,
+                                         get_commit_tree(new_branch_info->commit),
+                                         work,
+                                         get_commit_tree(old_branch_info->commit),
+                                         &result);
                        if (ret < 0)
                                exit(128);
-                       ret = reset_tree(new_branch_info->commit->tree, opts, 0,
+                       ret = reset_tree(get_commit_tree(new_branch_info->commit),
+                                        opts, 0,
                                         writeout_error);
                        strbuf_release(&o.obuf);
                        if (ret)
@@ -1002,7 +1008,7 @@ static int parse_branchname_arg(int argc, const char **argv,
                *source_tree = parse_tree_indirect(rev);
        } else {
                parse_commit_or_die(new_branch_info->commit);
-               *source_tree = new_branch_info->commit->tree;
+               *source_tree = get_commit_tree(new_branch_info->commit);
        }
 
        if (!*source_tree)                   /* case (1): want a tree */
index 84f1473..99e73da 100644 (file)
@@ -14,6 +14,7 @@
 #include "parse-options.h"
 #include "fetch-pack.h"
 #include "refs.h"
+#include "refspec.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
@@ -546,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
 }
 
 static struct ref *wanted_peer_refs(const struct ref *refs,
-               struct refspec *refspec)
+               struct refspec_item *refspec)
 {
        struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
        struct ref *local_refs = head;
@@ -823,7 +824,7 @@ static void write_refspec_config(const char *src_ref_prefix,
                        } else if (remote_head_points_at) {
                                const char *head = remote_head_points_at->name;
                                if (!skip_prefix(head, "refs/heads/", &head))
-                                       die("BUG: remote HEAD points at non-head?");
+                                       BUG("remote HEAD points at non-head?");
 
                                strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
                                                branch_top->buf, head);
@@ -894,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        int err = 0, complete_refs_before_fetch = 1;
        int submodule_progress;
 
-       struct refspec *refspec;
-       const char *fetch_pattern;
+       struct refspec_item refspec;
 
        fetch_if_missing = 0;
 
@@ -1077,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (option_required_reference.nr || option_optional_reference.nr)
                setup_reference();
 
-       fetch_pattern = value.buf;
-       refspec = parse_fetch_refspec(1, &fetch_pattern);
+       refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
 
        strbuf_reset(&value);
 
@@ -1138,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        refs = transport_get_remote_refs(transport, NULL);
 
        if (refs) {
-               mapped_refs = wanted_peer_refs(refs, refspec);
+               mapped_refs = wanted_peer_refs(refs, &refspec);
                /*
                 * transport_get_remote_refs() may return refs with null sha-1
                 * in mapped_refs (see struct transport->get_refs_list
@@ -1232,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        strbuf_release(&value);
        junk_mode = JUNK_LEAVE_ALL;
 
-       free(refspec);
+       refspec_item_clear(&refspec);
        return err;
 }
index 0c3223d..5228ccf 100644 (file)
@@ -42,7 +42,6 @@ int cmd_column(int argc, const char **argv, const char *prefix)
                git_config(column_config, NULL);
 
        memset(&copts, 0, sizeof(copts));
-       copts.width = term_columns();
        copts.padding = 1;
        argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
        if (argc)
index 5571d4a..a842fea 100644 (file)
@@ -143,6 +143,16 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
+static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)
+{
+       const char **value = opt->value;
+       if (arg != NULL && *arg == '=')
+               arg = arg + 1;
+
+       *value = arg;
+       return 0;
+}
+
 static void determine_whence(struct wt_status *s)
 {
        if (file_exists(git_path_merge_head()))
@@ -161,9 +171,9 @@ static void determine_whence(struct wt_status *s)
 static void status_init_config(struct wt_status *s, config_fn_t fn)
 {
        wt_status_prepare(s);
+       init_diff_ui_defaults();
        git_config(fn, s);
        determine_whence(s);
-       init_diff_ui_defaults();
        s->hints = advice_status_hints; /* must come after git_config() */
 }
 
@@ -495,7 +505,7 @@ static int is_a_merge(const struct commit *current_head)
 static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
 {
        if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
-               die("BUG: unable to parse our own ident: %s", buf->buf);
+               BUG("unable to parse our own ident: %s", buf->buf);
 }
 
 static void export_one(const char *var, const char *s, const char *e, int hack)
@@ -1259,11 +1269,31 @@ static int git_status_config(const char *k, const char *v, void *cb)
                        return error(_("Invalid untracked files mode '%s'"), v);
                return 0;
        }
+       if (!strcmp(k, "diff.renamelimit")) {
+               if (s->rename_limit == -1)
+                       s->rename_limit = git_config_int(k, v);
+               return 0;
+       }
+       if (!strcmp(k, "status.renamelimit")) {
+               s->rename_limit = git_config_int(k, v);
+               return 0;
+       }
+       if (!strcmp(k, "diff.renames")) {
+               if (s->detect_rename == -1)
+                       s->detect_rename = git_config_rename(k, v);
+               return 0;
+       }
+       if (!strcmp(k, "status.renames")) {
+               s->detect_rename = git_config_rename(k, v);
+               return 0;
+       }
        return git_diff_ui_config(k, v, NULL);
 }
 
 int cmd_status(int argc, const char **argv, const char *prefix)
 {
+       static int no_renames = -1;
+       static const char *rename_score_arg = (const char *)-1;
        static struct wt_status s;
        int fd;
        struct object_id oid;
@@ -1297,6 +1327,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                  N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
                OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
+               OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
+               { OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg,
+                 N_("n"), N_("detect renames, optionally set similarity index"),
+                 PARSE_OPT_OPTARG, opt_parse_rename_score },
                OPT_END(),
        };
 
@@ -1336,6 +1370,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        s.ignore_submodule_arg = ignore_submodule_arg;
        s.status_format = status_format;
        s.verbose = verbose;
+       if (no_renames != -1)
+               s.detect_rename = !no_renames;
+       if ((intptr_t)rename_score_arg != -1) {
+               if (s.detect_rename < DIFF_DETECT_RENAME)
+                       s.detect_rename = DIFF_DETECT_RENAME;
+               if (rename_score_arg)
+                       s.rename_score = parse_rename_score(&rename_score_arg);
+       }
 
        wt_status_collect(&s);
 
index 69e7270..b29d26d 100644 (file)
@@ -398,7 +398,7 @@ static char *normalize_value(const char *key, const char *value)
                return xstrdup(value);
        }
 
-       die("BUG: cannot normalize type %d", type);
+       BUG("cannot normalize type %d", type);
 }
 
 static int get_color_found;
@@ -602,6 +602,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        if (use_local_config && nongit)
                die(_("--local can only be used inside a git repository"));
 
+       if (given_config_source.blob && nongit)
+               die(_("--blob can only be used inside a git repository"));
+
        if (given_config_source.file &&
                        !strcmp(given_config_source.file, "-")) {
                given_config_source.file = NULL;
index b054713..d51e2ce 100644 (file)
@@ -66,7 +66,7 @@ static int count_loose(const struct object_id *oid, const char *path, void *data
        else {
                loose_size += on_disk_bytes(st);
                loose++;
-               if (verbose && has_sha1_pack(oid->hash))
+               if (verbose && has_object_pack(oid))
                        packed_loose++;
        }
        return 0;
index b5afc45..cf1ae77 100644 (file)
@@ -502,7 +502,7 @@ static void describe(const char *arg, int last_one)
 
        if (cmit)
                describe_commit(&oid, &sb);
-       else if (oid_object_info(&oid, NULL) == OBJ_BLOB)
+       else if (oid_object_info(the_repository, &oid, NULL) == OBJ_BLOB)
                describe_blob(oid, &sb);
        else
                die(_("%s is neither a commit nor blob"), arg);
@@ -612,7 +612,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                                suffix = broken;
                        }
                } else if (dirty) {
-                       static struct lock_file index_lock;
+                       struct lock_file index_lock = LOCK_INIT;
                        struct rev_info revs;
                        struct argv_array args = ARGV_ARRAY_INIT;
                        int fd, result;
index 16bfb22..bfefff3 100644 (file)
@@ -398,7 +398,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                if (!obj)
                        die(_("invalid object '%s' given."), name);
                if (obj->type == OBJ_COMMIT)
-                       obj = &((struct commit *)obj)->tree->object;
+                       obj = &get_commit_tree(((struct commit *)obj))->object;
 
                if (obj->type == OBJ_TREE) {
                        obj->flags |= flags;
index aad0e07..162806f 100644 (file)
@@ -610,7 +610,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
                        continue;
 
                if (!indices_loaded) {
-                       static struct lock_file lock;
+                       struct lock_file lock = LOCK_INIT;
                        strbuf_reset(&buf);
                        strbuf_addf(&buf, "%s/wtindex", tmpdir);
                        if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
index 530df12..6c97687 100644 (file)
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "config.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "object.h"
 #include "tag.h"
@@ -35,8 +36,7 @@ static int use_done_feature;
 static int no_data;
 static int full_tree;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct refspec *refspecs;
-static int refspecs_nr;
+static struct refspec refspecs = REFSPEC_INIT_FETCH;
 static int anonymize;
 
 static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -156,15 +156,14 @@ static void anonymize_path(struct strbuf *out, const char *path,
        }
 }
 
-/* Since intptr_t is C99, we do not use it here */
-static inline uint32_t *mark_to_ptr(uint32_t mark)
+static inline void *mark_to_ptr(uint32_t mark)
 {
-       return ((uint32_t *)NULL) + mark;
+       return (void *)(uintptr_t)mark;
 }
 
 static inline uint32_t ptr_to_mark(void * mark)
 {
-       return (uint32_t *)mark - (uint32_t *)NULL;
+       return (uint32_t)(uintptr_t)mark;
 }
 
 static inline void mark_object(struct object *object, uint32_t mark)
@@ -517,7 +516,7 @@ static void anonymize_ident_line(const char **beg, const char **end)
        /* skip "committer", "author", "tagger", etc */
        end_of_header = strchr(*beg, ' ');
        if (!end_of_header)
-               die("BUG: malformed line fed to anonymize_ident_line: %.*s",
+               BUG("malformed line fed to anonymize_ident_line: %.*s",
                    (int)(*end - *beg), *beg);
        end_of_header++;
        strbuf_add(out, *beg, end_of_header - *beg);
@@ -578,11 +577,11 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
            get_object_mark(&commit->parents->item->object) != 0 &&
            !full_tree) {
                parse_commit_or_die(commit->parents->item);
-               diff_tree_oid(&commit->parents->item->tree->object.oid,
-                             &commit->tree->object.oid, "", &rev->diffopt);
+               diff_tree_oid(get_commit_tree_oid(commit->parents->item),
+                             get_commit_tree_oid(commit), "", &rev->diffopt);
        }
        else
-               diff_root_tree_oid(&commit->tree->object.oid,
+               diff_root_tree_oid(get_commit_tree_oid(commit),
                                   "", &rev->diffopt);
 
        /* Export the referenced blobs, and remember the marks. */
@@ -829,9 +828,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
                if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
                        continue;
 
-               if (refspecs) {
+               if (refspecs.nr) {
                        char *private;
-                       private = apply_refspecs(refspecs, refspecs_nr, full_name);
+                       private = apply_refspecs(&refspecs, full_name);
                        if (private) {
                                free(full_name);
                                full_name = private;
@@ -950,7 +949,7 @@ static void import_marks(char *input_file)
                if (last_idnum < mark)
                        last_idnum = mark;
 
-               type = oid_object_info(&oid, NULL);
+               type = oid_object_info(the_repository, &oid, NULL);
                if (type < 0)
                        die("object not found: %s", oid_to_hex(&oid));
 
@@ -977,8 +976,8 @@ static void import_marks(char *input_file)
 static void handle_deletes(void)
 {
        int i;
-       for (i = 0; i < refspecs_nr; i++) {
-               struct refspec *refspec = &refspecs[i];
+       for (i = 0; i < refspecs.nr; i++) {
+               struct refspec_item *refspec = &refspecs.items[i];
                if (*refspec->src)
                        continue;
 
@@ -1039,18 +1038,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                usage_with_options (fast_export_usage, options);
 
        if (refspecs_list.nr) {
-               const char **refspecs_str;
                int i;
 
-               ALLOC_ARRAY(refspecs_str, refspecs_list.nr);
                for (i = 0; i < refspecs_list.nr; i++)
-                       refspecs_str[i] = refspecs_list.items[i].string;
-
-               refspecs_nr = refspecs_list.nr;
-               refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str);
+                       refspec_append(&refspecs, refspecs_list.items[i].string);
 
                string_list_clear(&refspecs_list, 1);
-               free(refspecs_str);
        }
 
        if (use_done_feature)
@@ -1089,7 +1082,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        if (use_done_feature)
                printf("done\n");
 
-       free_refspec(refspecs_nr, refspecs);
+       refspec_clear(&refspecs);
 
        return 0;
 }
index 7ee83ac..c0d8ad1 100644 (file)
@@ -5,6 +5,7 @@
 #include "config.h"
 #include "repository.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "builtin.h"
 #include "string-list.h"
@@ -59,9 +60,9 @@ static const char *submodule_prefix = "";
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
 static int shown_url = 0;
-static int refmap_alloc, refmap_nr;
-static const char **refmap_array;
+static struct refspec refmap = REFSPEC_INIT_FETCH;
 static struct list_objects_filter_options filter_options;
+static struct string_list server_options = STRING_LIST_INIT_DUP;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -107,14 +108,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
 
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
 {
-       ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
-
        /*
         * "git fetch --refmap='' origin foo"
         * can be used to tell the command not to store anywhere
         */
-       if (*arg)
-               refmap_array[refmap_nr++] = arg;
+       refspec_append(&refmap, arg);
+
        return 0;
 }
 
@@ -170,6 +169,7 @@ static struct option builtin_fetch_options[] = {
                 N_("accept refs that update .git/shallow")),
        { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
          N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
+       OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
        OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
                        TRANSPORT_FAMILY_IPV4),
        OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
@@ -202,7 +202,7 @@ static void add_merge_config(struct ref **head,
 
        for (i = 0; i < branch->merge_nr; i++) {
                struct ref *rm, **old_tail = *tail;
-               struct refspec refspec;
+               struct refspec_item refspec;
 
                for (rm = *head; rm; rm = rm->next) {
                        if (branch_merge_matches(branch, i, rm->name)) {
@@ -339,7 +339,7 @@ static void find_non_local_tags(struct transport *transport,
 }
 
 static struct ref *get_ref_map(struct transport *transport,
-                              struct refspec *refspecs, int refspec_count,
+                              struct refspec *rs,
                               int tags, int *autotags)
 {
        int i;
@@ -353,29 +353,26 @@ static struct ref *get_ref_map(struct transport *transport,
 
        const struct ref *remote_refs;
 
-       for (i = 0; i < refspec_count; i++) {
-               if (!refspecs[i].exact_sha1) {
-                       const char *glob = strchr(refspecs[i].src, '*');
-                       if (glob)
-                               argv_array_pushf(&ref_prefixes, "%.*s",
-                                                (int)(glob - refspecs[i].src),
-                                                refspecs[i].src);
-                       else
-                               expand_ref_prefix(&ref_prefixes, refspecs[i].src);
-               }
+       if (rs->nr)
+               refspec_ref_prefixes(rs, &ref_prefixes);
+       else if (transport->remote && transport->remote->fetch.nr)
+               refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
+
+       if (ref_prefixes.argc &&
+           (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
+               argv_array_push(&ref_prefixes, "refs/tags/");
        }
 
        remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
 
        argv_array_clear(&ref_prefixes);
 
-       if (refspec_count) {
+       if (rs->nr) {
                struct refspec *fetch_refspec;
-               int fetch_refspec_nr;
 
-               for (i = 0; i < refspec_count; i++) {
-                       get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
-                       if (refspecs[i].dst && refspecs[i].dst[0])
+               for (i = 0; i < rs->nr; i++) {
+                       get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
+                       if (rs->items[i].dst && rs->items[i].dst[0])
                                *autotags = 1;
                }
                /* Merge everything on the command line (but not --tags) */
@@ -402,17 +399,14 @@ static struct ref *get_ref_map(struct transport *transport,
                 * by ref_remove_duplicates() in favor of one of these
                 * opportunistic entries with FETCH_HEAD_IGNORE.
                 */
-               if (refmap_array) {
-                       fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
-                       fetch_refspec_nr = refmap_nr;
-               } else {
-                       fetch_refspec = transport->remote->fetch;
-                       fetch_refspec_nr = transport->remote->fetch_refspec_nr;
-               }
+               if (refmap.nr)
+                       fetch_refspec = &refmap;
+               else
+                       fetch_refspec = &transport->remote->fetch;
 
-               for (i = 0; i < fetch_refspec_nr; i++)
-                       get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
-       } else if (refmap_array) {
+               for (i = 0; i < fetch_refspec->nr; i++)
+                       get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
+       } else if (refmap.nr) {
                die("--refmap option is only meaningful with command-line refspec(s).");
        } else {
                /* Use the defaults */
@@ -420,16 +414,16 @@ static struct ref *get_ref_map(struct transport *transport,
                struct branch *branch = branch_get(NULL);
                int has_merge = branch_has_merge_config(branch);
                if (remote &&
-                   (remote->fetch_refspec_nr ||
+                   (remote->fetch.nr ||
                     /* Note: has_merge implies non-NULL branch->remote_name */
                     (has_merge && !strcmp(branch->remote_name, remote->name)))) {
-                       for (i = 0; i < remote->fetch_refspec_nr; i++) {
-                               get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0);
-                               if (remote->fetch[i].dst &&
-                                   remote->fetch[i].dst[0])
+                       for (i = 0; i < remote->fetch.nr; i++) {
+                               get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
+                               if (remote->fetch.items[i].dst &&
+                                   remote->fetch.items[i].dst[0])
                                        *autotags = 1;
                                if (!i && !has_merge && ref_map &&
-                                   !remote->fetch[0].pattern)
+                                   !remote->fetch.items[0].pattern)
                                        ref_map->fetch_head_status = FETCH_HEAD_MERGE;
                        }
                        /*
@@ -654,7 +648,7 @@ static int update_local_ref(struct ref *ref,
        struct branch *current_branch = branch_get(NULL);
        const char *pretty_ref = prettify_refname(ref->name);
 
-       type = oid_object_info(&ref->new_oid, NULL);
+       type = oid_object_info(the_repository, &ref->new_oid, NULL);
        if (type < 0)
                die(_("object %s not found"), oid_to_hex(&ref->new_oid));
 
@@ -964,11 +958,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
        return ret;
 }
 
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
-               const char *raw_url)
+static int prune_refs(struct refspec *rs, struct ref *ref_map,
+                     const char *raw_url)
 {
        int url_len, i, result = 0;
-       struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+       struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
        char *url;
        int summary_width = transport_summary_width(stale_refs);
        const char *dangling_msg = dry_run
@@ -1114,7 +1108,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
 }
 
 static int do_fetch(struct transport *transport,
-                   struct refspec *refs, int ref_count)
+                   struct refspec *rs)
 {
        struct string_list existing_refs = STRING_LIST_INIT_DUP;
        struct ref *ref_map;
@@ -1138,7 +1132,7 @@ static int do_fetch(struct transport *transport,
                        goto cleanup;
        }
 
-       ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
+       ref_map = get_ref_map(transport, rs, tags, &autotags);
        if (!update_head_ok)
                check_not_current_branch(ref_map);
 
@@ -1162,11 +1156,10 @@ static int do_fetch(struct transport *transport,
                 * explicitly (via command line or configuration); we
                 * don't care whether --tags was specified.
                 */
-               if (ref_count) {
-                       prune_refs(refs, ref_count, ref_map, transport->url);
+               if (rs->nr) {
+                       prune_refs(rs, ref_map, transport->url);
                } else {
-                       prune_refs(transport->remote->fetch,
-                                  transport->remote->fetch_refspec_nr,
+                       prune_refs(&transport->remote->fetch,
                                   ref_map,
                                   transport->url);
                }
@@ -1355,10 +1348,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
 
 static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
 {
-       static const char **refs = NULL;
-       struct refspec *refspec;
-       int ref_nr = 0;
-       int j = 0;
+       struct refspec rs = REFSPEC_INIT_FETCH;
+       int i;
        int exit_code;
        int maybe_prune_tags;
        int remote_via_config = remote_is_configured(remote, 0);
@@ -1391,37 +1382,34 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 
        maybe_prune_tags = prune_tags_ok && prune_tags;
        if (maybe_prune_tags && remote_via_config)
-               add_prune_tags_to_fetch_refspec(remote);
-
-       if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
-               size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
-               refs = xcalloc(nr_alloc, sizeof(const char *));
-               if (maybe_prune_tags) {
-                       refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
-                       ref_nr++;
+               refspec_append(&remote->fetch, TAG_REFSPEC);
+
+       if (maybe_prune_tags && (argc || !remote_via_config))
+               refspec_append(&rs, TAG_REFSPEC);
+
+       for (i = 0; i < argc; i++) {
+               if (!strcmp(argv[i], "tag")) {
+                       char *tag;
+                       i++;
+                       if (i >= argc)
+                               die(_("You need to specify a tag name."));
+
+                       tag = xstrfmt("refs/tags/%s:refs/tags/%s",
+                                     argv[i], argv[i]);
+                       refspec_append(&rs, tag);
+                       free(tag);
+               } else {
+                       refspec_append(&rs, argv[i]);
                }
        }
 
-       if (argc > 0) {
-               int i;
-               for (i = 0; i < argc; i++) {
-                       if (!strcmp(argv[i], "tag")) {
-                               i++;
-                               if (i >= argc)
-                                       die(_("You need to specify a tag name."));
-                               refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s",
-                                                   argv[i], argv[i]);
-                       } else
-                               refs[j++] = argv[i];
-                       ref_nr++;
-               }
-       }
+       if (server_options.nr)
+               gtransport->server_options = &server_options;
 
        sigchain_push_common(unlock_pack_on_signal);
        atexit(unlock_pack);
-       refspec = parse_fetch_refspec(ref_nr, refs);
-       exit_code = do_fetch(gtransport, refspec, ref_nr);
-       free_refspec(ref_nr, refspec);
+       exit_code = do_fetch(gtransport, &rs);
+       refspec_clear(&rs);
        transport_disconnect(gtransport);
        gtransport = NULL;
        return exit_code;
index 087360a..3ad4f16 100644 (file)
@@ -67,7 +67,8 @@ static const char *printable_type(struct object *obj)
        const char *ret;
 
        if (obj->type == OBJ_NONE) {
-               enum object_type type = oid_object_info(&obj->oid, NULL);
+               enum object_type type = oid_object_info(the_repository,
+                                                       &obj->oid, NULL);
                if (type > 0)
                        object_as_type(obj, type, 0);
        }
@@ -227,7 +228,7 @@ static void check_reachable_object(struct object *obj)
        if (!(obj->flags & HAS_OBJ)) {
                if (is_promisor_object(&obj->oid))
                        return;
-               if (has_sha1_pack(obj->oid.hash))
+               if (has_object_pack(&obj->oid))
                        return; /* it is in pack - forget about it */
                printf("missing %s %s\n", printable_type(obj),
                        describe_object(obj));
@@ -339,7 +340,7 @@ static void check_connectivity(void)
        }
 }
 
-static int fsck_obj(struct object *obj)
+static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 {
        int err;
 
@@ -353,7 +354,7 @@ static int fsck_obj(struct object *obj)
 
        if (fsck_walk(obj, NULL, &fsck_obj_options))
                objerror(obj, "broken links");
-       err = fsck_object(obj, NULL, 0, &fsck_obj_options);
+       err = fsck_object(obj, buffer, size, &fsck_obj_options);
        if (err)
                goto out;
 
@@ -398,7 +399,7 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
        }
        obj->flags &= ~(REACHABLE | SEEN);
        obj->flags |= HAS_OBJ;
-       return fsck_obj(obj);
+       return fsck_obj(obj, buffer, size);
 }
 
 static int default_refs;
@@ -506,44 +507,42 @@ static void get_default_heads(void)
        }
 }
 
-static struct object *parse_loose_object(const struct object_id *oid,
-                                        const char *path)
+static int fsck_loose(const struct object_id *oid, const char *path, void *data)
 {
        struct object *obj;
-       void *contents;
        enum object_type type;
        unsigned long size;
+       void *contents;
        int eaten;
 
-       if (read_loose_object(path, oid, &type, &size, &contents) < 0)
-               return NULL;
+       if (read_loose_object(path, oid, &type, &size, &contents) < 0) {
+               errors_found |= ERROR_OBJECT;
+               error("%s: object corrupt or missing: %s",
+                     oid_to_hex(oid), path);
+               return 0; /* keep checking other objects */
+       }
 
        if (!contents && type != OBJ_BLOB)
-               die("BUG: read_loose_object streamed a non-blob");
+               BUG("read_loose_object streamed a non-blob");
 
        obj = parse_object_buffer(oid, type, size, contents, &eaten);
-
-       if (!eaten)
-               free(contents);
-       return obj;
-}
-
-static int fsck_loose(const struct object_id *oid, const char *path, void *data)
-{
-       struct object *obj = parse_loose_object(oid, path);
-
        if (!obj) {
                errors_found |= ERROR_OBJECT;
-               error("%s: object corrupt or missing: %s",
+               error("%s: object could not be parsed: %s",
                      oid_to_hex(oid), path);
+               if (!eaten)
+                       free(contents);
                return 0; /* keep checking other objects */
        }
 
        obj->flags &= ~(REACHABLE | SEEN);
        obj->flags |= HAS_OBJ;
-       if (fsck_obj(obj))
+       if (fsck_obj(obj, contents, size))
                errors_found |= ERROR_OBJECT;
-       return 0;
+
+       if (!eaten)
+               free(contents);
+       return 0; /* keep checking other objects, even if we saw an error */
 }
 
 static int fsck_cruft(const char *basename, const char *path, void *data)
@@ -755,6 +754,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        }
                        stop_progress(&progress);
                }
+
+               if (fsck_finish(&fsck_obj_options))
+                       errors_found |= ERROR_OBJECT;
        }
 
        for (i = 0; i < argc; i++) {
index d604940..ccfb1ce 100644 (file)
 #include "commit.h"
 #include "packfile.h"
 #include "object-store.h"
+#include "pack.h"
+#include "pack-objects.h"
+#include "blob.h"
+#include "tree.h"
 
 #define FAILED_RUN "failed to run %s"
 
@@ -41,6 +45,8 @@ static timestamp_t gc_log_expire_time;
 static const char *gc_log_expire = "1.day.ago";
 static const char *prune_expire = "2.weeks.ago";
 static const char *prune_worktrees_expire = "3.months.ago";
+static unsigned long big_pack_threshold;
+static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 
 static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
 static struct argv_array reflog = ARGV_ARRAY_INIT;
@@ -128,6 +134,9 @@ static void gc_config(void)
        git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
        git_config_get_expiry("gc.logexpiry", &gc_log_expire);
 
+       git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
+       git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
+
        git_config(git_default_config, NULL);
 }
 
@@ -166,6 +175,28 @@ static int too_many_loose_objects(void)
        return needed;
 }
 
+static struct packed_git *find_base_packs(struct string_list *packs,
+                                         unsigned long limit)
+{
+       struct packed_git *p, *base = NULL;
+
+       for (p = get_packed_git(the_repository); p; p = p->next) {
+               if (!p->pack_local)
+                       continue;
+               if (limit) {
+                       if (p->pack_size >= limit)
+                               string_list_append(packs, p->pack_name);
+               } else if (!base || base->pack_size < p->pack_size) {
+                       base = p;
+               }
+       }
+
+       if (base)
+               string_list_append(packs, base->pack_name);
+
+       return base;
+}
+
 static int too_many_packs(void)
 {
        struct packed_git *p;
@@ -188,7 +219,86 @@ static int too_many_packs(void)
        return gc_auto_pack_limit < cnt;
 }
 
-static void add_repack_all_option(void)
+static uint64_t total_ram(void)
+{
+#if defined(HAVE_SYSINFO)
+       struct sysinfo si;
+
+       if (!sysinfo(&si))
+               return si.totalram;
+#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM))
+       int64_t physical_memory;
+       int mib[2];
+       size_t length;
+
+       mib[0] = CTL_HW;
+# if defined(HW_MEMSIZE)
+       mib[1] = HW_MEMSIZE;
+# else
+       mib[1] = HW_PHYSMEM;
+# endif
+       length = sizeof(int64_t);
+       if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
+               return physical_memory;
+#elif defined(GIT_WINDOWS_NATIVE)
+       MEMORYSTATUSEX memInfo;
+
+       memInfo.dwLength = sizeof(MEMORYSTATUSEX);
+       if (GlobalMemoryStatusEx(&memInfo))
+               return memInfo.ullTotalPhys;
+#endif
+       return 0;
+}
+
+static uint64_t estimate_repack_memory(struct packed_git *pack)
+{
+       unsigned long nr_objects = approximate_object_count();
+       size_t os_cache, heap;
+
+       if (!pack || !nr_objects)
+               return 0;
+
+       /*
+        * First we have to scan through at least one pack.
+        * Assume enough room in OS file cache to keep the entire pack
+        * or we may accidentally evict data of other processes from
+        * the cache.
+        */
+       os_cache = pack->pack_size + pack->index_size;
+       /* then pack-objects needs lots more for book keeping */
+       heap = sizeof(struct object_entry) * nr_objects;
+       /*
+        * internal rev-list --all --objects takes up some memory too,
+        * let's say half of it is for blobs
+        */
+       heap += sizeof(struct blob) * nr_objects / 2;
+       /*
+        * and the other half is for trees (commits and tags are
+        * usually insignificant)
+        */
+       heap += sizeof(struct tree) * nr_objects / 2;
+       /* and then obj_hash[], underestimated in fact */
+       heap += sizeof(struct object *) * nr_objects;
+       /* revindex is used also */
+       heap += sizeof(struct revindex_entry) * nr_objects;
+       /*
+        * read_sha1_file() (either at delta calculation phase, or
+        * writing phase) also fills up the delta base cache
+        */
+       heap += delta_base_cache_limit;
+       /* and of course pack-objects has its own delta cache */
+       heap += max_delta_cache_size;
+
+       return os_cache + heap;
+}
+
+static int keep_one_pack(struct string_list_item *item, void *data)
+{
+       argv_array_pushf(&repack, "--keep-pack=%s", basename(item->string));
+       return 0;
+}
+
+static void add_repack_all_option(struct string_list *keep_pack)
 {
        if (prune_expire && !strcmp(prune_expire, "now"))
                argv_array_push(&repack, "-a");
@@ -197,6 +307,9 @@ static void add_repack_all_option(void)
                if (prune_expire)
                        argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
        }
+
+       if (keep_pack)
+               for_each_string_list(keep_pack, keep_one_pack, NULL);
 }
 
 static void add_repack_incremental_option(void)
@@ -219,9 +332,35 @@ static int need_to_gc(void)
         * we run "repack -A -d -l".  Otherwise we tell the caller
         * there is no need.
         */
-       if (too_many_packs())
-               add_repack_all_option();
-       else if (too_many_loose_objects())
+       if (too_many_packs()) {
+               struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+               if (big_pack_threshold) {
+                       find_base_packs(&keep_pack, big_pack_threshold);
+                       if (keep_pack.nr >= gc_auto_pack_limit) {
+                               big_pack_threshold = 0;
+                               string_list_clear(&keep_pack, 0);
+                               find_base_packs(&keep_pack, 0);
+                       }
+               } else {
+                       struct packed_git *p = find_base_packs(&keep_pack, 0);
+                       uint64_t mem_have, mem_want;
+
+                       mem_have = total_ram();
+                       mem_want = estimate_repack_memory(p);
+
+                       /*
+                        * Only allow 1/2 of memory for pack-objects, leave
+                        * the rest for the OS and other processes in the
+                        * system.
+                        */
+                       if (!mem_have || mem_want < mem_have / 2)
+                               string_list_clear(&keep_pack, 0);
+               }
+
+               add_repack_all_option(&keep_pack);
+               string_list_clear(&keep_pack, 0);
+       } else if (too_many_loose_objects())
                add_repack_incremental_option();
        else
                return 0;
@@ -234,7 +373,7 @@ static int need_to_gc(void)
 /* return NULL on success, else hostname running the gc */
 static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
 {
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        char my_host[HOST_NAME_MAX + 1];
        struct strbuf sb = STRBUF_INIT;
        struct stat st;
@@ -354,6 +493,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        const char *name;
        pid_t pid;
        int daemonized = 0;
+       int keep_base_pack = -1;
        timestamp_t dummy;
 
        struct option builtin_gc_options[] = {
@@ -367,6 +507,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                OPT_BOOL_F(0, "force", &force,
                           N_("force running gc even if there may be another gc running"),
                           PARSE_OPT_NOCOMPLETE),
+               OPT_BOOL(0, "keep-largest-pack", &keep_base_pack,
+                        N_("repack all other packs except the largest pack")),
                OPT_END()
        };
 
@@ -435,8 +577,19 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                         */
                        daemonized = !daemonize();
                }
-       } else
-               add_repack_all_option();
+       } else {
+               struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+               if (keep_base_pack != -1) {
+                       if (keep_base_pack)
+                               find_base_packs(&keep_pack, 0);
+               } else if (big_pack_threshold) {
+                       find_base_packs(&keep_pack, big_pack_threshold);
+               }
+
+               add_repack_all_option(&keep_pack);
+               string_list_clear(&keep_pack, 0);
+       }
 
        name = lock_repo_for_gc(force, &pid);
        if (name) {
index 6e7bc76..69f0743 100644 (file)
@@ -488,7 +488,8 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
                strbuf_addstr(&name, repo->submodule_prefix);
        }
 
-       repo_read_index(repo);
+       if (repo_read_index(repo) < 0)
+               die("index file corrupt");
 
        for (nr = 0; nr < repo->index->cache_nr; nr++) {
                const struct cache_entry *ce = repo->index->cache[nr];
index a2cd29d..4ab31ed 100644 (file)
@@ -223,7 +223,7 @@ static unsigned check_object(struct object *obj)
 
        if (!(obj->flags & FLAG_CHECKED)) {
                unsigned long size;
-               int type = oid_object_info(&obj->oid, &size);
+               int type = oid_object_info(the_repository, &obj->oid, &size);
                if (type <= 0)
                        die(_("did not receive expected object %s"),
                              oid_to_hex(&obj->oid));
@@ -812,7 +812,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                enum object_type has_type;
                unsigned long has_size;
                read_lock();
-               has_type = oid_object_info(oid, &has_size);
+               has_type = oid_object_info(the_repository, oid, &has_size);
                if (has_type < 0)
                        die(_("cannot read existing object info %s"), oid_to_hex(oid));
                if (has_type != type || has_size != size)
@@ -837,6 +837,9 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                                blob->object.flags |= FLAG_CHECKED;
                        else
                                die(_("invalid blob object %s"), oid_to_hex(oid));
+                       if (do_fsck_object &&
+                           fsck_object(&blob->object, (void *)data, size, &fsck_options))
+                               die(_("fsck error in packed object"));
                } else {
                        struct object *obj;
                        int eaten;
@@ -854,7 +857,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                                die(_("invalid %s"), type_name(type));
                        if (do_fsck_object &&
                            fsck_object(obj, buf, size, &fsck_options))
-                               die(_("Error in object"));
+                               die(_("fsck error in packed object"));
                        if (strict && fsck_walk(obj, NULL, &fsck_options))
                                die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
 
@@ -866,7 +869,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        if (obj->type == OBJ_COMMIT) {
                                struct commit *commit = (struct commit *) obj;
                                if (detach_commit_buffer(commit, NULL) != data)
-                                       die("BUG: parse_object_buffer transmogrified our buffer");
+                                       BUG("parse_object_buffer transmogrified our buffer");
                        }
                        obj->flags |= FLAG_CHECKED;
                }
@@ -1015,7 +1018,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 
                if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
                                           base->obj->real_type))
-                       die("BUG: child->real_type != OBJ_REF_DELTA");
+                       BUG("child->real_type != OBJ_REF_DELTA");
 
                resolve_delta(child, base, result);
                if (base->ref_first == base->ref_last && base->ofs_last == -1)
@@ -1479,6 +1482,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
        } else
                chmod(final_index_name, 0444);
 
+       if (do_fsck_object)
+               add_packed_git(final_index_name, strlen(final_index_name), 0);
+
        if (!from_stdin) {
                printf("%s\n", sha1_to_hex(hash));
        } else {
@@ -1543,12 +1549,13 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
 {
        const uint32_t *idx1, *idx2;
        uint32_t i;
+       const uint32_t hashwords = the_hash_algo->rawsz / sizeof(uint32_t);
 
        /* The address of the 4-byte offset table */
        idx1 = (((const uint32_t *)p->index_data)
                + 2 /* 8-byte header */
                + 256 /* fan out */
-               + 5 * p->num_objects /* 20-byte SHA-1 table */
+               + hashwords * p->num_objects /* object ID table */
                + p->num_objects /* CRC32 table */
                );
 
@@ -1820,6 +1827,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                      pack_hash);
        else
                close(input_fd);
+
+       if (do_fsck_object && fsck_finish(&fsck_options))
+               die(_("fsck error in pack objects"));
+
        free(objects);
        strbuf_release(&index_name_buf);
        if (pack_name == NULL)
index 2542c52..5a5844c 100644 (file)
@@ -391,7 +391,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
                else if (get_shared_repository() == PERM_EVERYBODY)
                        xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
                else
-                       die("BUG: invalid value for shared_repository");
+                       BUG("invalid value for shared_repository");
                git_config_set("core.sharedrepository", buf);
                git_config_set("receive.denyNonFastforwards", "true");
        }
index 71f68a3..a15599f 100644 (file)
@@ -1019,7 +1019,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
            open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
                return;
 
-       log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte);
+       log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
 
        for (i = 0; !need_8bit_cte && i < nr; i++) {
                const char *buf = get_commit_buffer(list[i], NULL);
@@ -1067,8 +1067,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 
        diff_setup_done(&opts);
 
-       diff_tree_oid(&origin->tree->object.oid,
-                     &head->tree->object.oid,
+       diff_tree_oid(get_commit_tree_oid(origin),
+                     get_commit_tree_oid(head),
                      "", &opts);
        diffcore_std(&opts);
        diff_flush(&opts);
index a71f6bd..967b2b3 100644 (file)
@@ -166,7 +166,7 @@ static void show_killed_files(const struct index_state *istate,
                                 */
                                pos = index_name_pos(istate, ent->name, ent->len);
                                if (0 <= pos)
-                                       die("BUG: killed-file %.*s not found",
+                                       BUG("killed-file %.*s not found",
                                                ent->len, ent->name);
                                pos = -pos - 1;
                                while (pos < istate->cache_nr &&
index ca3f04a..1a25df7 100644 (file)
@@ -47,6 +47,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
        const char **pattern = NULL;
        struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
        int i;
+       struct string_list server_options = STRING_LIST_INIT_DUP;
 
        struct remote *remote;
        struct transport *transport;
@@ -73,6 +74,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                              2, PARSE_OPT_NOCOMPLETE),
                OPT_BOOL(0, "symref", &show_symref_target,
                         N_("show underlying ref in addition to the object pointed by it")),
+               OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
                OPT_END()
        };
 
@@ -116,6 +118,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
        transport = transport_get(remote, NULL);
        if (uploadpack != NULL)
                transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
+       if (server_options.nr)
+               transport->server_options = &server_options;
 
        ref = transport_get_remote_refs(transport, &ref_prefixes);
        if (transport_disconnect(transport)) {
index d44b4f9..409da4e 100644 (file)
@@ -94,7 +94,7 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
                        char size_text[24];
                        if (!strcmp(type, blob_type)) {
                                unsigned long size;
-                               if (oid_object_info(oid, &size) == OBJ_BAD)
+                               if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
                                        xsnprintf(size_text, sizeof(size_text),
                                                  "BAD");
                                else
index 9db5a2c..d85f99b 100644 (file)
@@ -14,6 +14,7 @@
 #include "run-command.h"
 #include "diff.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "diffcore.h"
 #include "revision.h"
@@ -280,7 +281,7 @@ out:
        return rc;
 }
 
-static void read_empty(unsigned const char *sha1, int verbose)
+static void read_empty(const struct object_id *oid, int verbose)
 {
        int i = 0;
        const char *args[7];
@@ -290,15 +291,15 @@ static void read_empty(unsigned const char *sha1, int verbose)
                args[i++] = "-v";
        args[i++] = "-m";
        args[i++] = "-u";
-       args[i++] = EMPTY_TREE_SHA1_HEX;
-       args[i++] = sha1_to_hex(sha1);
+       args[i++] = empty_tree_oid_hex();
+       args[i++] = oid_to_hex(oid);
        args[i] = NULL;
 
        if (run_command_v_opt(args, RUN_GIT_CMD))
                die(_("read-tree failed"));
 }
 
-static void reset_hard(unsigned const char *sha1, int verbose)
+static void reset_hard(const struct object_id *oid, int verbose)
 {
        int i = 0;
        const char *args[6];
@@ -308,7 +309,7 @@ static void reset_hard(unsigned const char *sha1, int verbose)
                args[i++] = "-v";
        args[i++] = "--reset";
        args[i++] = "-u";
-       args[i++] = sha1_to_hex(sha1);
+       args[i++] = oid_to_hex(oid);
        args[i] = NULL;
 
        if (run_command_v_opt(args, RUN_GIT_CMD))
@@ -324,7 +325,7 @@ static void restore_state(const struct object_id *head,
        if (is_null_oid(stash))
                return;
 
-       reset_hard(head->hash, 1);
+       reset_hard(head, 1);
 
        args[2] = oid_to_hex(stash);
 
@@ -647,7 +648,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                              struct commit_list *remoteheads,
                              struct commit *head)
 {
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        const char *head_arg = "HEAD";
 
        hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
@@ -805,7 +806,7 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
 {
        struct object_id result_tree, result_commit;
        struct commit_list *parents, **pptr = &parents;
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
 
        hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
        refresh_cache(REFRESH_QUIET);
@@ -1297,7 +1298,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (remoteheads->next)
                        die(_("Can merge only exactly one commit into empty head"));
                remote_head_oid = &remoteheads->item->object.oid;
-               read_empty(remote_head_oid->hash, 0);
+               read_empty(remote_head_oid, 0);
                update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
                           UPDATE_REFS_DIE_ON_ERR);
                goto done;
index 263c530..bb76b46 100644 (file)
@@ -116,7 +116,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
        }
 
        /* Check the type of object identified by sha1 */
-       obj_type = oid_object_info(&oid, NULL);
+       obj_type = oid_object_info(the_repository, &oid, NULL);
        if (obj_type < 0) {
                if (allow_missing) {
                        ; /* no problem - missing objects are presumed to be of the right type */
index 7a63667..80bb967 100644 (file)
@@ -72,7 +72,6 @@ static const char *add_slash(const char *path)
        return path;
 }
 
-static struct lock_file lock_file;
 #define SUBMODULE_WITH_GITDIR ((const char *)1)
 
 static void prepare_move_submodule(const char *src, int first,
@@ -131,6 +130,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
        struct stat st;
        struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+       struct lock_file lock_file = LOCK_INIT;
 
        git_config(git_default_config, NULL);
 
index e5bf80e..da279cd 100644 (file)
@@ -461,7 +461,7 @@ static int add(int argc, const char **argv, const char *prefix)
        if (d.buf.len || allow_empty) {
                write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
-                       die("BUG: combine_notes_overwrite failed");
+                       BUG("combine_notes_overwrite failed");
                commit_notes(t, "Notes added by 'git notes add'");
        } else {
                fprintf(stderr, _("Removing note for object %s\n"),
@@ -544,7 +544,7 @@ static int copy(int argc, const char **argv, const char *prefix)
        }
 
        if (add_note(t, &object, from_note, combine_notes_overwrite))
-               die("BUG: combine_notes_overwrite failed");
+               BUG("combine_notes_overwrite failed");
        commit_notes(t, "Notes added by 'git notes copy'");
 out:
        free_notes(t);
@@ -621,7 +621,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        if (d.buf.len || allow_empty) {
                write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
-                       die("BUG: combine_notes_overwrite failed");
+                       BUG("combine_notes_overwrite failed");
                logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
        } else {
                fprintf(stderr, _("Removing note for object %s\n"),
@@ -831,7 +831,7 @@ static int merge(int argc, const char **argv, const char *prefix)
                const char *short_ref = NULL;
 
                if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref))
-                       die("BUG: local ref %s is outside of refs/notes/",
+                       BUG("local ref %s is outside of refs/notes/",
                            o.local_ref);
 
                strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref);
index 24b1c6c..e78f3f5 100644 (file)
 #include "list.h"
 #include "packfile.h"
 #include "object-store.h"
+#include "dir.h"
+
+#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
+#define SIZE(obj) oe_size(&to_pack, obj)
+#define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size)
+#define DELTA_SIZE(obj) oe_delta_size(&to_pack, obj)
+#define DELTA(obj) oe_delta(&to_pack, obj)
+#define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj)
+#define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj)
+#define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val)
+#define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val)
+#define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val)
+#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
 
 static const char *pack_usage[] = {
        N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
@@ -45,7 +58,7 @@ static const char *pack_usage[] = {
 static struct packing_data to_pack;
 
 static struct pack_idx_entry **written_list;
-static uint32_t nr_result, nr_written;
+static uint32_t nr_result, nr_written, nr_seen;
 
 static int non_empty;
 static int reuse_delta = 1, reuse_object = 1;
@@ -55,7 +68,8 @@ static int pack_loose_unreachable;
 static int local;
 static int have_non_local_packs;
 static int incremental;
-static int ignore_packed_keep;
+static int ignore_packed_keep_on_disk;
+static int ignore_packed_keep_in_core;
 static int allow_ofs_delta;
 static struct pack_idx_option pack_idx_opts;
 static const char *base_name;
@@ -80,7 +94,7 @@ static uint16_t write_bitmap_options;
 static int exclude_promisor_objects;
 
 static unsigned long delta_cache_size = 0;
-static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
+static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 static unsigned long cache_max_small_delta_size = 1000;
 
 static unsigned long window_memory_limit = 0;
@@ -127,13 +141,14 @@ static void *get_delta(struct object_entry *entry)
        buf = read_object_file(&entry->idx.oid, &type, &size);
        if (!buf)
                die("unable to read %s", oid_to_hex(&entry->idx.oid));
-       base_buf = read_object_file(&entry->delta->idx.oid, &type, &base_size);
+       base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
+                                   &base_size);
        if (!base_buf)
                die("unable to read %s",
-                   oid_to_hex(&entry->delta->idx.oid));
+                   oid_to_hex(&DELTA(entry)->idx.oid));
        delta_buf = diff_delta(base_buf, base_size,
                               buf, size, &delta_size, 0);
-       if (!delta_buf || delta_size != entry->delta_size)
+       if (!delta_buf || delta_size != DELTA_SIZE(entry))
                die("delta size changed");
        free(buf);
        free(base_buf);
@@ -264,10 +279,11 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
        enum object_type type;
        void *buf;
        struct git_istream *st = NULL;
+       const unsigned hashsz = the_hash_algo->rawsz;
 
        if (!usable_delta) {
-               if (entry->type == OBJ_BLOB &&
-                   entry->size > big_file_threshold &&
+               if (oe_type(entry) == OBJ_BLOB &&
+                   oe_size_greater_than(&to_pack, entry, big_file_threshold) &&
                    (st = open_istream(&entry->idx.oid, &type, &size, NULL)) != NULL)
                        buf = NULL;
                else {
@@ -283,15 +299,15 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
                FREE_AND_NULL(entry->delta_data);
                entry->z_delta_size = 0;
        } else if (entry->delta_data) {
-               size = entry->delta_size;
+               size = DELTA_SIZE(entry);
                buf = entry->delta_data;
                entry->delta_data = NULL;
-               type = (allow_ofs_delta && entry->delta->idx.offset) ?
+               type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
                        OBJ_OFS_DELTA : OBJ_REF_DELTA;
        } else {
                buf = get_delta(entry);
-               size = entry->delta_size;
-               type = (allow_ofs_delta && entry->delta->idx.offset) ?
+               size = DELTA_SIZE(entry);
+               type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
                        OBJ_OFS_DELTA : OBJ_REF_DELTA;
        }
 
@@ -315,12 +331,12 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
                 * encoding of the relative offset for the delta
                 * base from this object's position in the pack.
                 */
-               off_t ofs = entry->idx.offset - entry->delta->idx.offset;
+               off_t ofs = entry->idx.offset - DELTA(entry)->idx.offset;
                unsigned pos = sizeof(dheader) - 1;
                dheader[pos] = ofs & 127;
                while (ofs >>= 7)
                        dheader[--pos] = 128 | (--ofs & 127);
-               if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+               if (limit && hdrlen + sizeof(dheader) - pos + datalen + hashsz >= limit) {
                        if (st)
                                close_istream(st);
                        free(buf);
@@ -332,19 +348,19 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
        } else if (type == OBJ_REF_DELTA) {
                /*
                 * Deltas with a base reference contain
-                * an additional 20 bytes for the base sha1.
+                * additional bytes for the base object ID.
                 */
-               if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+               if (limit && hdrlen + hashsz + datalen + hashsz >= limit) {
                        if (st)
                                close_istream(st);
                        free(buf);
                        return 0;
                }
                hashwrite(f, header, hdrlen);
-               hashwrite(f, entry->delta->idx.oid.hash, 20);
-               hdrlen += 20;
+               hashwrite(f, DELTA(entry)->idx.oid.hash, hashsz);
+               hdrlen += hashsz;
        } else {
-               if (limit && hdrlen + datalen + 20 >= limit) {
+               if (limit && hdrlen + datalen + hashsz >= limit) {
                        if (st)
                                close_istream(st);
                        free(buf);
@@ -367,21 +383,23 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
 static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
                                unsigned long limit, int usable_delta)
 {
-       struct packed_git *p = entry->in_pack;
+       struct packed_git *p = IN_PACK(entry);
        struct pack_window *w_curs = NULL;
        struct revindex_entry *revidx;
        off_t offset;
-       enum object_type type = entry->type;
+       enum object_type type = oe_type(entry);
        off_t datalen;
        unsigned char header[MAX_PACK_OBJECT_HEADER],
                      dheader[MAX_PACK_OBJECT_HEADER];
        unsigned hdrlen;
+       const unsigned hashsz = the_hash_algo->rawsz;
+       unsigned long entry_size = SIZE(entry);
 
-       if (entry->delta)
-               type = (allow_ofs_delta && entry->delta->idx.offset) ?
+       if (DELTA(entry))
+               type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
                        OBJ_OFS_DELTA : OBJ_REF_DELTA;
        hdrlen = encode_in_pack_object_header(header, sizeof(header),
-                                             type, entry->size);
+                                             type, entry_size);
 
        offset = entry->in_pack_offset;
        revidx = find_pack_revindex(p, offset);
@@ -398,7 +416,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
        datalen -= entry->in_pack_header_size;
 
        if (!pack_to_stdout && p->index_version == 1 &&
-           check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
+           check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
                error("corrupt packed object for %s",
                      oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
@@ -406,12 +424,12 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
        }
 
        if (type == OBJ_OFS_DELTA) {
-               off_t ofs = entry->idx.offset - entry->delta->idx.offset;
+               off_t ofs = entry->idx.offset - DELTA(entry)->idx.offset;
                unsigned pos = sizeof(dheader) - 1;
                dheader[pos] = ofs & 127;
                while (ofs >>= 7)
                        dheader[--pos] = 128 | (--ofs & 127);
-               if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+               if (limit && hdrlen + sizeof(dheader) - pos + datalen + hashsz >= limit) {
                        unuse_pack(&w_curs);
                        return 0;
                }
@@ -420,16 +438,16 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
                hdrlen += sizeof(dheader) - pos;
                reused_delta++;
        } else if (type == OBJ_REF_DELTA) {
-               if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+               if (limit && hdrlen + hashsz + datalen + hashsz >= limit) {
                        unuse_pack(&w_curs);
                        return 0;
                }
                hashwrite(f, header, hdrlen);
-               hashwrite(f, entry->delta->idx.oid.hash, 20);
-               hdrlen += 20;
+               hashwrite(f, DELTA(entry)->idx.oid.hash, hashsz);
+               hdrlen += hashsz;
                reused_delta++;
        } else {
-               if (limit && hdrlen + datalen + 20 >= limit) {
+               if (limit && hdrlen + datalen + hashsz >= limit) {
                        unuse_pack(&w_curs);
                        return 0;
                }
@@ -465,28 +483,29 @@ static off_t write_object(struct hashfile *f,
        else
                limit = pack_size_limit - write_offset;
 
-       if (!entry->delta)
+       if (!DELTA(entry))
                usable_delta = 0;       /* no delta */
        else if (!pack_size_limit)
               usable_delta = 1;        /* unlimited packfile */
-       else if (entry->delta->idx.offset == (off_t)-1)
+       else if (DELTA(entry)->idx.offset == (off_t)-1)
                usable_delta = 0;       /* base was written to another pack */
-       else if (entry->delta->idx.offset)
+       else if (DELTA(entry)->idx.offset)
                usable_delta = 1;       /* base already exists in this pack */
        else
                usable_delta = 0;       /* base could end up in another pack */
 
        if (!reuse_object)
                to_reuse = 0;   /* explicit */
-       else if (!entry->in_pack)
+       else if (!IN_PACK(entry))
                to_reuse = 0;   /* can't reuse what we don't have */
-       else if (entry->type == OBJ_REF_DELTA || entry->type == OBJ_OFS_DELTA)
+       else if (oe_type(entry) == OBJ_REF_DELTA ||
+                oe_type(entry) == OBJ_OFS_DELTA)
                                /* check_object() decided it for us ... */
                to_reuse = usable_delta;
                                /* ... but pack split may override that */
-       else if (entry->type != entry->in_pack_type)
+       else if (oe_type(entry) != entry->in_pack_type)
                to_reuse = 0;   /* pack has delta which is unusable */
-       else if (entry->delta)
+       else if (DELTA(entry))
                to_reuse = 0;   /* we want to pack afresh */
        else
                to_reuse = 1;   /* we have it in-pack undeltified,
@@ -538,12 +557,12 @@ static enum write_one_status write_one(struct hashfile *f,
        }
 
        /* if we are deltified, write out base object first. */
-       if (e->delta) {
+       if (DELTA(e)) {
                e->idx.offset = 1; /* now recurse */
-               switch (write_one(f, e->delta, offset)) {
+               switch (write_one(f, DELTA(e), offset)) {
                case WRITE_ONE_RECURSIVE:
                        /* we cannot depend on this one */
-                       e->delta = NULL;
+                       SET_DELTA(e, NULL);
                        break;
                default:
                        break;
@@ -605,34 +624,34 @@ static void add_descendants_to_write_order(struct object_entry **wo,
                        /* add this node... */
                        add_to_write_order(wo, endp, e);
                        /* all its siblings... */
-                       for (s = e->delta_sibling; s; s = s->delta_sibling) {
+                       for (s = DELTA_SIBLING(e); s; s = DELTA_SIBLING(s)) {
                                add_to_write_order(wo, endp, s);
                        }
                }
                /* drop down a level to add left subtree nodes if possible */
-               if (e->delta_child) {
+               if (DELTA_CHILD(e)) {
                        add_to_order = 1;
-                       e = e->delta_child;
+                       e = DELTA_CHILD(e);
                } else {
                        add_to_order = 0;
                        /* our sibling might have some children, it is next */
-                       if (e->delta_sibling) {
-                               e = e->delta_sibling;
+                       if (DELTA_SIBLING(e)) {
+                               e = DELTA_SIBLING(e);
                                continue;
                        }
                        /* go back to our parent node */
-                       e = e->delta;
-                       while (e && !e->delta_sibling) {
+                       e = DELTA(e);
+                       while (e && !DELTA_SIBLING(e)) {
                                /* we're on the right side of a subtree, keep
                                 * going up until we can go right again */
-                               e = e->delta;
+                               e = DELTA(e);
                        }
                        if (!e) {
                                /* done- we hit our original root node */
                                return;
                        }
                        /* pass it off to sibling at this level */
-                       e = e->delta_sibling;
+                       e = DELTA_SIBLING(e);
                }
        };
 }
@@ -643,7 +662,7 @@ static void add_family_to_write_order(struct object_entry **wo,
 {
        struct object_entry *root;
 
-       for (root = e; root->delta; root = root->delta)
+       for (root = e; DELTA(root); root = DELTA(root))
                ; /*&n