Sync with maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 15 Nov 2017 03:17:43 +0000 (12:17 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 15 Nov 2017 03:17:43 +0000 (12:17 +0900)
205 files changed:
Documentation/.gitignore
Documentation/Makefile
Documentation/RelNotes/2.16.0.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/git-bisect.txt
Documentation/git-for-each-ref.txt
Documentation/git-merge.txt
Documentation/git-push.txt
Documentation/git-stash.txt
Documentation/git-status.txt
Documentation/gitworkflows.txt
Documentation/merge-options.txt
Documentation/technical/api-directory-listing.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
RelNotes
advice.c
advice.h
apply.c
apply.h
archive.c
bisect.c
bisect.h
blame.c
branch.c
builtin/add.c
builtin/am.c
builtin/apply.c
builtin/bisect--helper.c
builtin/blame.c
builtin/branch.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/describe.c
builtin/diff.c
builtin/difftool.c
builtin/fast-export.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/fsck.c
builtin/log.c
builtin/merge-base.c
builtin/merge-ours.c
builtin/merge.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/push.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/show-branch.c
builtin/show-ref.c
builtin/submodule--helper.c
builtin/symbolic-ref.c
builtin/tag.c
builtin/update-index.c
builtin/update-ref.c
builtin/worktree.c
bundle.c
cache-tree.c
cache.h
combine-diff.c
commit.c
commit.h
compat/obstack.c
compat/obstack.h
compat/poll/poll.c
compat/poll/poll.h
compat/regex/regcomp.c
compat/regex/regex.c
compat/regex/regex.h
compat/regex/regex_internal.c
compat/regex/regex_internal.h
compat/regex/regexec.c
config.c
connected.c
connected.h
contrib/completion/git-completion.bash
contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
contrib/credential/libsecret/git-credential-libsecret.c
contrib/emacs/git-blame.el
contrib/emacs/git.el
contrib/fast-import/import-directories.perl
contrib/hg-to-git/hg-to-git.py
contrib/mw-to-git/Git/Mediawiki.pm
contrib/mw-to-git/git-remote-mediawiki.perl
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-pickaxe.c
diffcore-rename.c
dir.c
dir.h
ewah/bitmap.c
ewah/ewah_bitmap.c
ewah/ewah_io.c
ewah/ewah_rlw.c
ewah/ewok.h
ewah/ewok_rlw.h
fast-import.c
git-bisect.sh
git-gui/git-gui.sh
git-rebase--interactive.sh
git-stash.sh
git-submodule.sh
gitweb/gitweb.perl
grep.c
grep.h
hex.c
http-push.c
imap-send.c
kwset.c
kwset.h
lockfile.h
log-tree.c
merge-recursive.c
merge.c
notes-cache.c
notes-merge.c
notes-utils.c
notes.c
pack-bitmap.c
pack-bitmap.h
patch-ids.c
pathspec.c
perl/Git/Packet.pm [new file with mode: 0644]
perl/Makefile
read-cache.c
ref-filter.c
reflog-walk.c
refs.c
refs.h
refs/files-backend.c
refs/packed-backend.c
refs/packed-backend.h
refs/ref-cache.c
refs/refs-internal.h
remote-testsvn.c
remote.c
remote.h
revision.c
run-command.c
sequencer.c
sh-i18n--envsubst.c
sha1_file.c
sha1_name.c
submodule-config.h
submodule.c
t/helper/test-ref-store.c
t/lib-submodule-update.sh
t/perf/p4211-line-log.sh
t/t0000-basic.sh
t/t0021/rot13-filter.pl
t/t0027-auto-crlf.sh
t/t1409-avoid-packing-refs.sh [new file with mode: 0755]
t/t3426-rebase-submodule.sh
t/t3600-rm.sh
t/t3700-add.sh
t/t4201-shortlog.sh
t/t5521-pull-options.sh
t/t5526-fetch-submodules.sh
t/t5545-push-options.sh
t/t6030-bisect-porcelain.sh
t/t6300-for-each-ref.sh
t/t7001-mv.sh
t/t7520-ignored-hook-warning.sh [new file with mode: 0755]
t/t7521-ignored-mode.sh [new file with mode: 0755]
t/t9114-git-svn-dcommit-merge.sh
t/test-lib.sh
tempfile.h
trace.c
transport-helper.c
transport.c
tree-diff.c
unpack-trees.c
upload-pack.c
walker.c
worktree.c
worktree.h
wrapper.c
wt-status.c
wt-status.h
xdiff/xdiff.h
xdiff/xdiffi.c
xdiff/xdiffi.h
xdiff/xemit.c
xdiff/xemit.h
xdiff/xinclude.h
xdiff/xmacros.h
xdiff/xmerge.c
xdiff/xpatience.c
xdiff/xprepare.c
xdiff/xprepare.h
xdiff/xtypes.h
xdiff/xutils.c
xdiff/xutils.h

index 2c8b2d6..c7096f1 100644 (file)
@@ -11,3 +11,4 @@ doc.dep
 cmds-*.txt
 mergetools-*.txt
 manpage-base-url.xsl
+SubmittingPatches.txt
index 471bb29..2ab6556 100644 (file)
@@ -67,6 +67,7 @@ SP_ARTICLES += howto/maintain-git
 API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
 SP_ARTICLES += $(API_DOCS)
 
+TECH_DOCS += SubmittingPatches
 TECH_DOCS += technical/hash-function-transition
 TECH_DOCS += technical/http-protocol
 TECH_DOCS += technical/index-format
@@ -181,6 +182,7 @@ ASCIIDOC = asciidoctor
 ASCIIDOC_CONF =
 ASCIIDOC_HTML = xhtml5
 ASCIIDOC_DOCBOOK = docbook45
+ASCIIDOC_EXTRA += -acompat-mode
 ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
 ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;'
 DBLATEX_COMMON =
@@ -323,6 +325,7 @@ clean:
        $(RM) *.pdf
        $(RM) howto-index.txt howto/*.html doc.dep
        $(RM) technical/*.html technical/api-index.txt
+       $(RM) SubmittingPatches.txt
        $(RM) $(cmds_txt) $(mergetools_txt) *.made
        $(RM) manpage-base-url.xsl
 
@@ -361,6 +364,9 @@ technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
 $(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt asciidoc.conf
        $(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
 
+SubmittingPatches.txt: SubmittingPatches
+       $(QUIET_GEN) cp $< $@
+
 XSLT = docbook.xsl
 XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
 
diff --git a/Documentation/RelNotes/2.16.0.txt b/Documentation/RelNotes/2.16.0.txt
new file mode 100644 (file)
index 0000000..12b86eb
--- /dev/null
@@ -0,0 +1,211 @@
+Git 2.16 Release Notes
+======================
+
+Backward compatibility notes and other notable changes.
+
+ * Use of an empty string as a pathspec element that is used for
+   'everything matches' is now an error.
+
+
+Updates since v2.15
+-------------------
+
+UI, Workflows & Features
+
+ * An empty string as a pathspec element that means "everything"
+   i.e. 'git add ""', is now illegal.  We started this by first
+   deprecating and warning a pathspec that has such an element in
+   2.11 (Nov 2016).
+
+ * A hook script that is set unexecutable is simply ignored.  Git
+   notifies when such a file is ignored, unless the message is
+   squelched via advice.ignoredHook configuration.
+
+ * "git pull" has been taught to accept "--[no-]signoff" option and
+   pass it down to "git merge".
+
+ * The "--push-option=<string>" option to "git push" now defaults to a
+   list of strings configured via push.pushOption variable.
+
+ * "gitweb" checks if a directory is searchable with Perl's "-x"
+   operator, which can be enhanced by using "filetest 'access'"
+   pragma, which now we do.
+
+ * "git stash save" has been deprecated in favour of "git stash push".
+
+ * The set of paths output from "git status --ignored" was tied
+   closely with its "--untracked=<mode>" option, but now it can be
+   controlled more flexibly.  Most notably, a directory that is
+   ignored because it is listed to be ignored in the ignore/exclude
+   mechanism can be handled differently from a directory that ends up
+   to be ignored only because all files in it are ignored.
+
+ * The remote-helper for talking to MediaWiki has been updated to
+   truncate an overlong pagename so that ".mw" suffix can still be
+   added.
+
+ * The remote-helper for talking to MediaWiki has been updated to
+   work with mediawiki namespaces.
+
+ * The "--format=..." option "git for-each-ref" takes learned to show
+   the name of the 'remote' repository and the ref at the remote side
+   that is affected for 'upstream' and 'push' via "%(push:remotename)"
+   and friends.
+
+ * Doc and message updates to teach users "bisect view" is a synonym
+   for "bisect visualize".
+
+ * "git bisect run" that did not specify any command to run used to go
+   ahead and treated all commits to be tested as 'good'.  This has
+   been corrected by making the command error out.
+
+ * The SubmittingPatches document has been converted to produce an
+   HTML version via AsciiDoc/Asciidoctor.
+   (merge 049e64aa50 bc/submitting-patches-in-asciidoc later to maint).
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * An earlier update made it possible to use an on-stack in-core
+   lockfile structure (as opposed to having to deliberately leak an
+   on-heap one).  Many codepaths have been updated to take advantage
+   of this new facility.
+
+ * Calling cmd_foo() as if it is a general purpose helper function is
+   a no-no.  Correct two instances of such to set an example.
+
+ * We try to see if somebody runs our test suite with a shell that
+   does not support "local" like bash/dash does.
+
+ * An early part of piece-by-piece rewrite of "git bisect" in C.
+
+ * GSoC to piece-by-piece rewrite "git submodule" in C.
+
+ * Optimize the code to find shortest unique prefix of object names.
+
+ * Pathspec-limited revision traversal was taught not to keep finding
+   unneeded differences once it knows two trees are different inside
+   given pathspec.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * Code cleanup.
+   (merge 62a24c8923 rs/hex-to-bytes-cleanup later to maint).
+
+ * A single-word "unsigned flags" in the diff options is being split
+   into a structure with many bitfields.
+   (merge 0d1e0e7801 bw/diff-opt-impl-to-bitfields later to maint).
+
+ * TravisCI build updates.
+
+ * Parts of a test to drive the long-running content filter interface
+   has been split into its own module, hopefully to eventually become
+   reusable.
+   (merge 0fe8d516bb cc/git-packet-pm later to maint).
+
+ * Drop (perhaps overly cautious) sanity check before using the index
+   read from the filesystem at runtime.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.15
+-----------------
+
+ * "auto" as a value for the columnar output configuration ought to
+   judge "is the output consumed by humans?" with the same criteria as
+   "auto" for coloured output configuration, i.e. either the standard
+   output stream is going to tty, or a pager is in use.  We forgot the
+   latter, which has been fixed.
+
+ * The experimental "color moved lines differently in diff output"
+   feature was buggy around "ignore whitespace changes" edges, whihch
+   has been corrected.
+
+ * Instead of using custom line comparison and hashing functions to
+   implement "moved lines" coloring in the diff output, use the pair
+   of these functions from lower-layer xdiff/ code.
+
+ * Some codepaths did not check for errors when asking what branch the
+   HEAD points at, which have been fixed.
+
+ * "git commit", after making a commit, did not check for errors when
+   asking on what branch it made the commit, which has been correted.
+
+ * "git status --ignored -u" did not stop at a working tree of a
+   separate project that is embedded in an ignored directory and
+   listed files in that other project, instead of just showing the
+   directory itself as ignored.
+
+ * A broken access to object databases in recent update to "git grep
+   --recurse-submodules" has been fixed.
+
+ * A recent regression in "git rebase -i" that broke execution of git
+   commands from subdirectories via "exec" insn has been fixed.
+
+ * A (possibly flakey) test fix.
+
+ * "git check-ref-format --branch @{-1}" bit a "BUG()" when run
+   outside a repository for obvious reasons; clarify the documentation
+   and make sure we do not even try to expand the at-mark magic in
+   such a case, but still call the validation logic for branch names.
+
+ * "git fetch --recurse-submodules" now knows that submodules can be
+   moved around in the superproject in addition to getting updated,
+   and finds the ones that need to be fetched accordingly.
+
+ * Command line completion (in contrib/) update.
+
+ * Description of blame.{showroot,blankboundary,showemail,date}
+   configuration variables have been added to "git config --help".
+
+ * After an error from lstat(), diff_populate_filespec() function
+   sometimes still went ahead and used invalid data in struct stat,
+   which has been fixed.
+
+ * UNC paths are also relevant in Cygwin builds and they are now
+   tested just like Mingw builds.
+
+ * Correct start-up sequence so that a repository could be placed
+   immediately under the root directory again (which was broken at
+   around Git 2.13).
+
+ * The credential helper for libsecret (in contrib/) has been improved
+   to allow possibly prompting the end user to unlock secrets that are
+   currently locked (otherwise the secrets may not be loaded).
+
+ * MinGW updates.
+
+ * Error checking in "git imap-send" for empty response has been
+   improved.
+   (merge 618ec81abb rs/imap-send-next-arg-fix later to maint).
+
+ * Recent update to the refs infrastructure implementation started
+   rewriting packed-refs file more often than before; this has been
+   optimized again for most trivial cases.
+   (merge 7c6bd25c7d mh/avoid-rewriting-packed-refs later to maint).
+
+ * Some error messages did not quote filenames shown in it, which have
+   been fixed.
+   (merge 0a288d1ee9 sr/wrapper-quote-filenames later to maint).
+
+ * "git rebase -i" recently started misbehaving when a submodule that
+   is configured with 'submodule.<name>.ignore' is dirty; this has
+   been corrected.
+   (merge c6d8ccf3a2 bw/rebase-i-ignored-submodule-fix later to maint).
+
+ * Building with NO_LIBPCRE1_JIT did not disable it, which has been fixed.
+   (merge 2fff1e196d ab/pcre-v2 later to maint).
+
+ * We used to add an empty alternate object database to the system
+   that does not help anything; it has been corrected.
+   (merge f28e36686a jk/info-alternates-fix later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge 804862209b ao/merge-verbosity-getenv-just-once later to maint).
+   (merge 9360ec0002 rs/sequencer-rewrite-file-cleanup later to maint).
+   (merge f4e45cb3eb ma/bisect-leakfix later to maint).
+   (merge 4da72644b7 ma/reduce-heads-leakfix later to maint).
+   (merge 3dc5433fd5 ad/rebase-i-serie-typofix later to maint).
+   (merge 5313bee032 tz/fsf-address-update later to maint).
+   (merge 5555a2aa4b cb/t4201-robustify later to maint).
index 558d465..17419f7 100644 (file)
@@ -1,40 +1,47 @@
+Submitting Patches
+==================
+
+== Guidelines
+
 Here are some guidelines for people who want to contribute their code
 to this software.
 
-(0) Decide what to base your work on.
+[[base-branch]]
+=== Decide what to base your work on.
 
 In general, always base your work on the oldest branch that your
 change is relevant to.
 
- - A bugfix should be based on 'maint' in general. If the bug is not
-   present in 'maint', base it on 'master'. For a bug that's not yet
-   in 'master', find the topic that introduces the regression, and
-   base your work on the tip of the topic.
+* A bugfix should be based on `maint` in general. If the bug is not
+  present in `maint`, base it on `master`. For a bug that's not yet
+  in `master`, find the topic that introduces the regression, and
+  base your work on the tip of the topic.
 
- - A new feature should be based on 'master' in general. If the new
-   feature depends on a topic that is in 'pu', but not in 'master',
-   base your work on the tip of that topic.
+* A new feature should be based on `master` in general. If the new
+  feature depends on a topic that is in `pu`, but not in `master`,
+  base your work on the tip of that topic.
 
- - Corrections and enhancements to a topic not yet in 'master' should
-   be based on the tip of that topic. If the topic has not been merged
-   to 'next', it's alright to add a note to squash minor corrections
-   into the series.
+* Corrections and enhancements to a topic not yet in `master` should
+  be based on the tip of that topic. If the topic has not been merged
+  to `next`, it's alright to add a note to squash minor corrections
+  into the series.
 
- - In the exceptional case that a new feature depends on several topics
-   not in 'master', start working on 'next' or 'pu' privately and send
-   out patches for discussion. Before the final merge, you may have to
-   wait until some of the dependent topics graduate to 'master', and
-   rebase your work.
+* In the exceptional case that a new feature depends on several topics
+  not in `master`, start working on `next` or `pu` privately and send
+  out patches for discussion. Before the final merge, you may have to
+  wait until some of the dependent topics graduate to `master`, and
+  rebase your work.
 
- - Some parts of the system have dedicated maintainers with their own
-   repositories (see the section "Subsystems" below).  Changes to
-   these parts should be based on their trees.
+* Some parts of the system have dedicated maintainers with their own
+  repositories (see the section "Subsystems" below).  Changes to
+  these parts should be based on their trees.
 
-To find the tip of a topic branch, run "git log --first-parent
-master..pu" and look for the merge commit. The second parent of this
+To find the tip of a topic branch, run `git log --first-parent
+master..pu` and look for the merge commit. The second parent of this
 commit is the tip of the topic branch.
 
-(1) Make separate commits for logically separate changes.
+[[separate-commits]]
+=== Make separate commits for logically separate changes.
 
 Unless your patch is really trivial, you should not be sending
 out a patch that was generated between your working tree and
@@ -58,8 +65,9 @@ differs substantially from the prior version, are all good things
 to have.
 
 Make sure that you have tests for the bug you are fixing.  See
-t/README for guidance.
+`t/README` for guidance.
 
+[[tests]]
 When adding a new feature, make sure that you have new tests to show
 the feature triggers the new behavior when it should, and to show the
 feature does not trigger when it shouldn't.  After any code change, make
@@ -84,41 +92,45 @@ turning en_UK spelling to en_US).  Obvious typographical fixes are much
 more welcomed ("teh -> "the"), preferably submitted as independent
 patches separate from other documentation changes.
 
+[[whitespace-check]]
 Oh, another thing.  We are picky about whitespaces.  Make sure your
 changes do not trigger errors with the sample pre-commit hook shipped
-in templates/hooks--pre-commit.  To help ensure this does not happen,
-run "git diff --check" on your changes before you commit.
+in `templates/hooks--pre-commit`.  To help ensure this does not happen,
+run `git diff --check` on your changes before you commit.
 
-
-(2) Describe your changes well.
+[[describe-changes]]
+=== Describe your changes well.
 
 The first line of the commit message should be a short description (50
-characters is the soft limit, see DISCUSSION in git-commit(1)), and
-should skip the full stop.  It is also conventional in most cases to
+characters is the soft limit, see DISCUSSION in linkgit:git-commit[1]),
+and should skip the full stop.  It is also conventional in most cases to
 prefix the first line with "area: " where the area is a filename or
 identifier for the general area of the code being modified, e.g.
 
-  . doc: clarify distinction between sign-off and pgp-signing
-  . githooks.txt: improve the intro section
+* doc: clarify distinction between sign-off and pgp-signing
+* githooks.txt: improve the intro section
 
-If in doubt which identifier to use, run "git log --no-merges" on the
+If in doubt which identifier to use, run `git log --no-merges` on the
 files you are modifying to see the current conventions.
 
+[[summary-section]]
 It's customary to start the remainder of the first line after "area: "
 with a lower-case letter. E.g. "doc: clarify...", not "doc:
 Clarify...", or "githooks.txt: improve...", not "githooks.txt:
 Improve...".
 
+[[meaningful-message]]
 The body should provide a meaningful commit message, which:
 
-  . explains the problem the change tries to solve, i.e. what is wrong
-    with the current code without the change.
+. explains the problem the change tries to solve, i.e. what is wrong
+  with the current code without the change.
 
-  . justifies the way the change solves the problem, i.e. why the
-    result with the change is better.
+. justifies the way the change solves the problem, i.e. why the
+  result with the change is better.
 
-  . alternate solutions considered but discarded, if any.
+. alternate solutions considered but discarded, if any.
 
+[[imperative-mood]]
 Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
 instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
 to do frotz", as if you are giving orders to the codebase to change
@@ -126,36 +138,43 @@ its behavior.  Try to make sure your explanation can be understood
 without external resources. Instead of giving a URL to a mailing list
 archive, summarize the relevant points of the discussion.
 
+[[commit-reference]]
 If you want to reference a previous commit in the history of a stable
 branch, use the format "abbreviated sha1 (subject, date)",
 with the subject enclosed in a pair of double-quotes, like this:
 
-    Commit f86a374 ("pack-bitmap.c: fix a memleak", 2015-03-30)
-    noticed that ...
+....
+       Commit f86a374 ("pack-bitmap.c: fix a memleak", 2015-03-30)
+       noticed that ...
+....
 
 The "Copy commit summary" command of gitk can be used to obtain this
-format, or this invocation of "git show":
+format, or this invocation of `git show`:
 
-    git show -s --date=short --pretty='format:%h ("%s", %ad)' <commit>
+....
+       git show -s --date=short --pretty='format:%h ("%s", %ad)' <commit>
+....
 
-(3) Generate your patch using Git tools out of your commits.
+[[git-tools]]
+=== Generate your patch using Git tools out of your commits.
 
 Git based diff tools generate unidiff which is the preferred format.
 
-You do not have to be afraid to use -M option to "git diff" or
-"git format-patch", if your patch involves file renames.  The
+You do not have to be afraid to use `-M` option to `git diff` or
+`git format-patch`, if your patch involves file renames.  The
 receiving end can handle them just fine.
 
+[[review-patch]]
 Please make sure your patch does not add commented out debugging code,
 or include any extra files which do not relate to what your patch
 is trying to achieve. Make sure to review
 your patch after generating it, to ensure accuracy.  Before
-sending out, please make sure it cleanly applies to the "master"
+sending out, please make sure it cleanly applies to the `master`
 branch head.  If you are preparing a work based on "next" branch,
 that is fine, but please mark it as such.
 
-
-(4) Sending your patches.
+[[send-patches]]
+=== Sending your patches.
 
 Learn to use format-patch and send-email if possible.  These commands
 are optimized for the workflow of sending patches, avoiding many ways
@@ -191,7 +210,7 @@ not ready to be applied but it is for discussion, [PATCH v2],
 [PATCH v3] etc. are often seen when you are sending an update to
 what you have previously sent.
 
-"git format-patch" command follows the best current practice to
+`git format-patch` command follows the best current practice to
 format the body of an e-mail message.  At the beginning of the
 patch should come your commit message, ending with the
 Signed-off-by: lines, and a line that consists of three dashes,
@@ -208,6 +227,7 @@ an explanation of changes between each iteration can be kept in
 Git-notes and inserted automatically following the three-dash
 line via `git format-patch --notes`.
 
+[[attachment]]
 Do not attach the patch as a MIME attachment, compressed or not.
 Do not let your e-mail client send quoted-printable.  Do not let
 your e-mail client send format=flowed which would destroy
@@ -222,6 +242,7 @@ that it will be postponed.
 Exception:  If your mailer is mangling patches then someone may ask
 you to re-send them using MIME, that is OK.
 
+[[pgp-signature]]
 Do not PGP sign your patch. Most likely, your maintainer or other people on the
 list would not have your PGP key and would not bother obtaining it anyway.
 Your patch is not judged by who you are; a good patch from an unknown origin
@@ -230,28 +251,27 @@ origin that is done poorly or does incorrect things.
 
 If you really really really really want to do a PGP signed
 patch, format it as "multipart/signed", not a text/plain message
-that starts with '-----BEGIN PGP SIGNED MESSAGE-----'.  That is
+that starts with `-----BEGIN PGP SIGNED MESSAGE-----`.  That is
 not a text/plain, it's something else.
 
 Send your patch with "To:" set to the mailing list, with "cc:" listing
 people who are involved in the area you are touching (the output from
-"git blame $path" and "git shortlog --no-merges $path" would help to
++git blame _$path_+ and +git shortlog {litdd}no-merges _$path_+ would help to
 identify them), to solicit comments and reviews.
 
+:1: footnote:[The current maintainer: gitster@pobox.com]
+:2: footnote:[The mailing list: git@vger.kernel.org]
+
 After the list reached a consensus that it is a good idea to apply the
-patch, re-send it with "To:" set to the maintainer [*1*] and "cc:" the
-list [*2*] for inclusion.
+patch, re-send it with "To:" set to the maintainer{1} and "cc:" the
+list{2} for inclusion.
 
-Do not forget to add trailers such as "Acked-by:", "Reviewed-by:" and
-"Tested-by:" lines as necessary to credit people who helped your
+Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
+`Tested-by:` lines as necessary to credit people who helped your
 patch.
 
-    [Addresses]
-     *1* The current maintainer: gitster@pobox.com
-     *2* The mailing list: git@vger.kernel.org
-
-
-(5) Certify your work by adding your "Signed-off-by: " line
+[[sign-off]]
+=== Certify your work by adding your "Signed-off-by: " line
 
 To improve tracking of who did what, we've borrowed the
 "sign-off" procedure from the Linux kernel project on patches
@@ -263,35 +283,39 @@ the patch, which certifies that you wrote it or otherwise have
 the right to pass it on as a open-source patch.  The rules are
 pretty simple: if you can certify the below D-C-O:
 
-        Developer's Certificate of Origin 1.1
-
-        By making a contribution to this project, I certify that:
-
-        (a) The contribution was created in whole or in part by me and I
-            have the right to submit it under the open source license
-            indicated in the file; or
-
-        (b) The contribution is based upon previous work that, to the best
-            of my knowledge, is covered under an appropriate open source
-            license and I have the right under that license to submit that
-            work with modifications, whether created in whole or in part
-            by me, under the same open source license (unless I am
-            permitted to submit under a different license), as indicated
-            in the file; or
-
-        (c) The contribution was provided directly to me by some other
-            person who certified (a), (b) or (c) and I have not modified
-            it.
-
-        (d) I understand and agree that this project and the contribution
-            are public and that a record of the contribution (including all
-            personal information I submit with it, including my sign-off) is
-            maintained indefinitely and may be redistributed consistent with
-            this project or the open source license(s) involved.
+[[dco]]
+.Developer's Certificate of Origin 1.1
+____
+By making a contribution to this project, I certify that:
+
+a. The contribution was created in whole or in part by me and I
+   have the right to submit it under the open source license
+   indicated in the file; or
+
+b. The contribution is based upon previous work that, to the best
+   of my knowledge, is covered under an appropriate open source
+   license and I have the right under that license to submit that
+   work with modifications, whether created in whole or in part
+   by me, under the same open source license (unless I am
+   permitted to submit under a different license), as indicated
+   in the file; or
+
+c. The contribution was provided directly to me by some other
+   person who certified (a), (b) or (c) and I have not modified
+   it.
+
+d. I understand and agree that this project and the contribution
+   are public and that a record of the contribution (including all
+   personal information I submit with it, including my sign-off) is
+   maintained indefinitely and may be redistributed consistent with
+   this project or the open source license(s) involved.
+____
 
 then you just add a line saying
 
-        Signed-off-by: Random J Developer <random@developer.example.org>
+....
+       Signed-off-by: Random J Developer <random@developer.example.org>
+....
 
 This line can be automatically added by Git if you run the git-commit
 command with the -s option.
@@ -302,85 +326,86 @@ D-C-O.  Indeed you are encouraged to do so.  Do not forget to
 place an in-body "From: " line at the beginning to properly attribute
 the change to its true author (see (2) above).
 
+[[real-name]]
 Also notice that a real name is used in the Signed-off-by: line. Please
 don't hide your real name.
 
+[[commit-trailers]]
 If you like, you can put extra tags at the end:
 
-1. "Reported-by:" is used to credit someone who found the bug that
-   the patch attempts to fix.
-2. "Acked-by:" says that the person who is more familiar with the area
-   the patch attempts to modify liked the patch.
-3. "Reviewed-by:", unlike the other tags, can only be offered by the
-   reviewer and means that she is completely satisfied that the patch
-   is ready for application.  It is usually offered only after a
-   detailed review.
-4. "Tested-by:" is used to indicate that the person applied the patch
-   and found it to have the desired effect.
+. `Reported-by:` is used to credit someone who found the bug that
+  the patch attempts to fix.
+. `Acked-by:` says that the person who is more familiar with the area
+  the patch attempts to modify liked the patch.
+. `Reviewed-by:`, unlike the other tags, can only be offered by the
+  reviewer and means that she is completely satisfied that the patch
+  is ready for application.  It is usually offered only after a
+  detailed review.
+. `Tested-by:` is used to indicate that the person applied the patch
+  and found it to have the desired effect.
 
 You can also create your own tag or use one that's in common usage
 such as "Thanks-to:", "Based-on-patch-by:", or "Mentored-by:".
 
-------------------------------------------------
-Subsystems with dedicated maintainers
+== Subsystems with dedicated maintainers
 
 Some parts of the system have dedicated maintainers with their own
 repositories.
 
- - git-gui/ comes from git-gui project, maintained by Pat Thoyts:
+- 'git-gui/' comes from git-gui project, maintained by Pat Thoyts:
 
-        git://repo.or.cz/git-gui.git
+       git://repo.or.cz/git-gui.git
 
- - gitk-git/ comes from Paul Mackerras's gitk project:
+- 'gitk-git/' comes from Paul Mackerras's gitk project:
 
-        git://ozlabs.org/~paulus/gitk
+       git://ozlabs.org/~paulus/gitk
 
- - po/ comes from the localization coordinator, Jiang Xin:
+- 'po/' comes from the localization coordinator, Jiang Xin:
 
        https://github.com/git-l10n/git-po/
 
 Patches to these parts should be based on their trees.
 
-------------------------------------------------
-An ideal patch flow
+[[patch-flow]]
+== An ideal patch flow
 
 Here is an ideal patch flow for this project the current maintainer
 suggests to the contributors:
 
- (0) You come up with an itch.  You code it up.
+. You come up with an itch.  You code it up.
 
- (1) Send it to the list and cc people who may need to know about
-     the change.
+. Send it to the list and cc people who may need to know about
+  the change.
++
+The people who may need to know are the ones whose code you
+are butchering.  These people happen to be the ones who are
+most likely to be knowledgeable enough to help you, but
+they have no obligation to help you (i.e. you ask for help,
+don't demand).  +git log -p {litdd} _$area_you_are_modifying_+ would
+help you find out who they are.
 
-     The people who may need to know are the ones whose code you
-     are butchering.  These people happen to be the ones who are
-     most likely to be knowledgeable enough to help you, but
-     they have no obligation to help you (i.e. you ask for help,
-     don't demand).  "git log -p -- $area_you_are_modifying" would
-     help you find out who they are.
+. You get comments and suggestions for improvements.  You may
+  even get them in a "on top of your change" patch form.
 
- (2) You get comments and suggestions for improvements.  You may
-     even get them in a "on top of your change" patch form.
+. Polish, refine, and re-send to the list and the people who
+  spend their time to improve your patch.  Go back to step (2).
 
- (3) Polish, refine, and re-send to the list and the people who
-     spend their time to improve your patch.  Go back to step (2).
+. The list forms consensus that the last round of your patch is
+  good.  Send it to the maintainer and cc the list.
 
- (4) The list forms consensus that the last round of your patch is
-     good.  Send it to the maintainer and cc the list.
-
- (5) A topic branch is created with the patch and is merged to 'next',
-     and cooked further and eventually graduates to 'master'.
+. A topic branch is created with the patch and is merged to `next`,
+  and cooked further and eventually graduates to `master`.
 
 In any time between the (2)-(3) cycle, the maintainer may pick it up
-from the list and queue it to 'pu', in order to make it easier for
+from the list and queue it to `pu`, in order to make it easier for
 people play with it without having to pick up and apply the patch to
 their trees themselves.
 
-------------------------------------------------
-Know the status of your patch after submission
+[[patch-status]]
+== Know the status of your patch after submission
 
 * You can use Git itself to find out when your patch is merged in
-  master. 'git pull --rebase' will automatically skip already-applied
+  master. `git pull --rebase` will automatically skip already-applied
   patches, and will let you know. This works only if you rebase on top
   of the branch in which your patch has been merged (i.e. it will not
   tell you if your patch is merged in pu if you rebase on top of
@@ -390,8 +415,8 @@ Know the status of your patch after submission
   entitled "What's cooking in git.git" and "What's in git.git" giving
   the status of various proposed changes.
 
---------------------------------------------------
-GitHub-Travis CI hints
+[[travis]]
+== GitHub-Travis CI hints
 
 With an account at GitHub (you can get one for free to work on open
 source projects), you can use Travis CI to test your changes on Linux,
@@ -400,25 +425,25 @@ test build here: https://travis-ci.org/git/git/builds/120473209
 
 Follow these steps for the initial setup:
 
- (1) Fork https://github.com/git/git to your GitHub account.
-     You can find detailed instructions how to fork here:
-     https://help.github.com/articles/fork-a-repo/
+. Fork https://github.com/git/git to your GitHub account.
+  You can find detailed instructions how to fork here:
+  https://help.github.com/articles/fork-a-repo/
 
- (2) Open the Travis CI website: https://travis-ci.org
+. Open the Travis CI website: https://travis-ci.org
 
- (3) Press the "Sign in with GitHub" button.
+. Press the "Sign in with GitHub" button.
 
- (4) Grant Travis CI permissions to access your GitHub account.
-     You can find more information about the required permissions here:
-     https://docs.travis-ci.com/user/github-oauth-scopes
+. Grant Travis CI permissions to access your GitHub account.
+  You can find more information about the required permissions here:
+  https://docs.travis-ci.com/user/github-oauth-scopes
 
- (5) Open your Travis CI profile page: https://travis-ci.org/profile
+. Open your Travis CI profile page: https://travis-ci.org/profile
 
- (6) Enable Travis CI builds for your Git fork.
+. Enable Travis CI builds for your Git fork.
 
 After the initial setup, Travis CI will run whenever you push new changes
 to your fork of Git on GitHub.  You can monitor the test state of all your
-branches here: https://travis-ci.org/<Your GitHub handle>/git/branches
+branches here: https://travis-ci.org/__<Your GitHub handle>__/git/branches
 
 If a branch did not pass all test cases then it is marked with a red
 cross.  In that case you can click on the failing Travis CI job and
@@ -430,17 +455,16 @@ example: https://travis-ci.org/git/git/jobs/122676187
 Fix the problem and push your fix to your Git fork.  This will trigger
 a new Travis CI build to ensure all tests pass.
 
-
-------------------------------------------------
-MUA specific hints
+[[mua]]
+== MUA specific hints
 
 Some of patches I receive or pick up from the list share common
 patterns of breakage.  Please make sure your MUA is set up
 properly not to corrupt whitespaces.
 
-See the DISCUSSION section of git-format-patch(1) for hints on
+See the DISCUSSION section of linkgit:git-format-patch[1] for hints on
 checking your patch by mailing it to yourself and applying with
-git-am(1).
+linkgit:git-am[1].
 
 While you are at it, check the resulting commit log message from
 a trial run of applying the patch.  If what is in the resulting
@@ -452,23 +476,24 @@ should come after the three-dash line that signals the end of the
 commit message.
 
 
-Pine
-----
+=== Pine
 
 (Johannes Schindelin)
 
+....
 I don't know how many people still use pine, but for those poor
 souls it may be good to mention that the quell-flowed-text is
 needed for recent versions.
 
 ... the "no-strip-whitespace-before-send" option, too. AFAIK it
 was introduced in 4.60.
+....
 
 (Linus Torvalds)
 
+....
 And 4.58 needs at least this.
 
----
 diff-tree 8326dd8350be64ac7fc805f6563a1d61ad10d32c (from e886a61f76edf5410573e92e38ce22974f9c40f1)
 Author: Linus Torvalds <torvalds@g5.osdl.org>
 Date:   Mon Aug 15 17:23:51 2005 -0700
@@ -490,10 +515,11 @@ diff --git a/pico/pico.c b/pico/pico.c
 +#endif
                c |= COMP_EXIT;
                break;
-
+....
 
 (Daniel Barkalow)
 
+....
 > A patch to SubmittingPatches, MUA specific help section for
 > users of Pine 4.63 would be very much appreciated.
 
@@ -503,23 +529,21 @@ that or Gentoo did it.) So you need to set the
 "no-strip-whitespace-before-send" option, unless the option you have is
 "strip-whitespace-before-send", in which case you should avoid checking
 it.
+....
 
+=== Thunderbird, KMail, GMail
 
-Thunderbird, KMail, GMail
--------------------------
-
-See the MUA-SPECIFIC HINTS section of git-format-patch(1).
+See the MUA-SPECIFIC HINTS section of linkgit:git-format-patch[1].
 
-Gnus
-----
+=== Gnus
 
-'|' in the *Summary* buffer can be used to pipe the current
+"|" in the `*Summary*` buffer can be used to pipe the current
 message to an external program, and this is a handy way to drive
-"git am".  However, if the message is MIME encoded, what is
+`git am`.  However, if the message is MIME encoded, what is
 piped into the program is the representation you see in your
-*Article* buffer after unwrapping MIME.  This is often not what
+`*Article*` buffer after unwrapping MIME.  This is often not what
 you would want for two reasons.  It tends to screw up non ASCII
 characters (most notably in people's names), and also
-whitespaces (fatal in patches).  Running 'C-u g' to display the
-message in raw form before using '|' to run the pipe can work
+whitespaces (fatal in patches).  Running "C-u g" to display the
+message in raw form before using "|" to run the pipe can work
 this problem around.
index 9593bfa..671fcba 100644 (file)
@@ -351,6 +351,9 @@ advice.*::
        addEmbeddedRepo::
                Advice on what to do when you've accidentally added one
                git repo inside of another.
+       ignoredHook::
+               Advice shown if an hook is ignored because the hook is not
+               set as executable.
 --
 
 core.fileMode::
@@ -2638,6 +2641,35 @@ push.gpgSign::
        override a value from a lower-priority config file. An explicit
        command-line flag always overrides this config option.
 
+push.pushOption::
+       When no `--push-option=<option>` argument is given from the
+       command line, `git push` behaves as if each <value> of
+       this variable is given as `--push-option=<value>`.
++
+This is a multi-valued variable, and an empty value can be used in a
+higher priority configuration file (e.g. `.git/config` in a
+repository) to clear the values inherited from a lower priority
+configuration files (e.g. `$HOME/.gitconfig`).
++
+--
+
+Example:
+
+/etc/gitconfig
+  push.pushoption = a
+  push.pushoption = b
+
+~/.gitconfig
+  push.pushoption = c
+
+repo/.git/config
+  push.pushoption =
+  push.pushoption = b
+
+This will result in only b (a and c are cleared).
+
+--
+
 push.recurseSubmodules::
        Make sure all submodule commits used by the revisions to be pushed
        are available on a remote-tracking branch. If the value is 'check'
index 6c42abf..4a1417b 100644 (file)
@@ -23,7 +23,7 @@ on the subcommand:
  git bisect terms [--term-good | --term-bad]
  git bisect skip [(<rev>|<range>)...]
  git bisect reset [<commit>]
- git bisect visualize
+ git bisect (visualize|view)
  git bisect replay <logfile>
  git bisect log
  git bisect run <cmd>...
@@ -193,24 +193,23 @@ git bisect start --term-new fixed --term-old broken
 Then, use `git bisect <term-old>` and `git bisect <term-new>` instead
 of `git bisect good` and `git bisect bad` to mark commits.
 
-Bisect visualize
-~~~~~~~~~~~~~~~~
+Bisect visualize/view
+~~~~~~~~~~~~~~~~~~~~~
 
 To see the currently remaining suspects in 'gitk', issue the following
-command during the bisection process:
+command during the bisection process (the subcommand `view` can be used
+as an alternative to `visualize`):
 
 ------------
 $ git bisect visualize
 ------------
 
-`view` may also be used as a synonym for `visualize`.
-
 If the `DISPLAY` environment variable is not set, 'git log' is used
 instead.  You can also give command-line options such as `-p` and
 `--stat`.
 
 ------------
-$ git bisect view --stat
+$ git bisect visualize --stat
 ------------
 
 Bisect log and bisect replay
index 1d420e4..dffa14a 100644 (file)
@@ -145,18 +145,25 @@ upstream::
        (behind), "<>" (ahead and behind), or "=" (in sync). `:track`
        also prints "[gone]" whenever unknown upstream ref is
        encountered. Append `:track,nobracket` to show tracking
-       information without brackets (i.e "ahead N, behind M").  Has
-       no effect if the ref does not have tracking information
-       associated with it.  All the options apart from `nobracket`
-       are mutually exclusive, but if used together the last option
-       is selected.
+       information without brackets (i.e "ahead N, behind M").
++
+For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`
+and `%(upstream:remoteref)` refer to the name of the remote and the
+name of the tracked remote ref, respectively. In other words, the
+remote-tracking branch can be updated explicitly and individually by
+using the refspec `%(upstream:remoteref):%(upstream)` to fetch from
+`%(upstream:remotename)`.
++
+Has no effect if the ref does not have tracking information associated
+with it.  All the options apart from `nobracket` are mutually exclusive,
+but if used together the last option is selected.
 
 push::
        The name of a local ref which represents the `@{push}`
        location for the displayed ref. Respects `:short`, `:lstrip`,
-       `:rstrip`, `:track`, and `:trackshort` options as `upstream`
-       does. Produces an empty string if no `@{push}` ref is
-       configured.
+       `:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`
+       options as `upstream` does. Produces an empty string if no `@{push}`
+       ref is configured.
 
 HEAD::
        '*' if HEAD matches current ref (the checked out branch), ' '
index 3c6927b..d5dfd84 100644 (file)
@@ -64,14 +64,6 @@ OPTIONS
 -------
 include::merge-options.txt[]
 
---signoff::
-       Add Signed-off-by line by the committer at the end of the commit
-       log message.  The meaning of a signoff depends on the project,
-       but it typically certifies that committer has
-       the rights to submit this work under the same license and
-       agrees to a Developer Certificate of Origin
-       (see http://developercertificate.org/ for more information).
-
 -m <msg>::
        Set the commit message to be used for the merge commit (in
        case one is created).
index 3e76e99..5b08302 100644 (file)
@@ -156,11 +156,17 @@ already exists on the remote side.
        Either all refs are updated, or on error, no refs are updated.
        If the server does not support atomic pushes the push will fail.
 
--o::
---push-option::
+-o <option>::
+--push-option=<option>::
        Transmit the given string to the server, which passes them to
        the pre-receive as well as the post-receive hook. The given string
        must not contain a NUL or LF character.
+       When multiple `--push-option=<option>` are given, they are
+       all sent to the other side in the order listed on the
+       command line.
+       When no `--push-option=<option>` is given from the command
+       line, the values of configuration variable `push.pushOption`
+       are used instead.
 
 --receive-pack=<git-receive-pack>::
 --exec=<git-receive-pack>::
index 00f95fe..8be6610 100644 (file)
@@ -13,8 +13,6 @@ SYNOPSIS
 'git stash' drop [-q|--quiet] [<stash>]
 'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
 'git stash' branch <branchname> [<stash>]
-'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
-            [-u|--include-untracked] [-a|--all] [<message>]
 'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
             [-u|--include-untracked] [-a|--all] [-m|--message <message>]]
             [--] [<pathspec>...]]
@@ -33,7 +31,7 @@ and reverts the working directory to match the `HEAD` commit.
 The modifications stashed away by this command can be listed with
 `git stash list`, inspected with `git stash show`, and restored
 (potentially on top of a different commit) with `git stash apply`.
-Calling `git stash` without any arguments is equivalent to `git stash save`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
 A stash is by default listed as "WIP on 'branchname' ...", but
 you can give a more descriptive message on the command line when
 you create one.
@@ -48,7 +46,6 @@ stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
 OPTIONS
 -------
 
-save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
 push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::
 
        Save your local modifications to a new 'stash entry' and roll them
@@ -87,6 +84,12 @@ linkgit:git-add[1] to learn how to operate the `--patch` mode.
 The `--patch` option implies `--keep-index`.  You can use
 `--no-keep-index` to override this.
 
+save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
+
+       This option is deprecated in favour of 'git stash push'.  It
+       differs from "stash push" in that it cannot take pathspecs,
+       and any non-option arguments form the message.
+
 list [<options>]::
 
        List the stash entries that you currently have.  Each 'stash entry' is
@@ -118,7 +121,7 @@ pop [--index] [-q|--quiet] [<stash>]::
 
        Remove a single stashed state from the stash list and apply it
        on top of the current working tree state, i.e., do the inverse
-       operation of `git stash save`. The working directory must
+       operation of `git stash push`. The working directory must
        match the index.
 +
 Applying the state can fail with conflicts; in this case, it is not
@@ -137,7 +140,7 @@ apply [--index] [-q|--quiet] [<stash>]::
 
        Like `pop`, but do not remove the state from the stash list. Unlike `pop`,
        `<stash>` may be any commit that looks like a commit created by
-       `stash save` or `stash create`.
+       `stash push` or `stash create`.
 
 branch <branchname> [<stash>]::
 
@@ -148,7 +151,7 @@ branch <branchname> [<stash>]::
        `stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>`
        is given, applies the latest one.
 +
-This is useful if the branch on which you ran `git stash save` has
+This is useful if the branch on which you ran `git stash push` has
 changed enough that `git stash apply` fails due to conflicts. Since
 the stash entry is applied on top of the commit that was HEAD at the
 time `git stash` was run, it restores the originally stashed state
@@ -255,14 +258,14 @@ $ git stash pop
 
 Testing partial commits::
 
-You can use `git stash save --keep-index` when you want to make two or
+You can use `git stash push --keep-index` when you want to make two or
 more commits out of the changes in the work tree, and you want to test
 each change before committing:
 +
 ----------------------------------------------------------------
 # ... hack hack hack ...
 $ git add --patch foo            # add just first part to the index
-$ git stash save --keep-index    # save all other changes to the stash
+$ git stash push --keep-index    # save all other changes to the stash
 $ edit/build/test first part
 $ git commit -m 'First part'     # commit fully tested change
 $ git stash pop                  # prepare to work on all other changes
index 9f3a78a..fc282e0 100644 (file)
@@ -97,8 +97,27 @@ configuration variable documented in linkgit:git-config[1].
        (and suppresses the output of submodule summaries when the config option
        `status.submoduleSummary` is set).
 
---ignored::
+--ignored[=<mode>]::
        Show ignored files as well.
++
+The mode parameter is used to specify the handling of ignored files.
+It is optional: it defaults to 'traditional'.
++
+The possible options are:
++
+       - 'traditional' - Shows ignored files and directories, unless
+                         --untracked-files=all is specifed, in which case
+                         individual files in ignored directories are
+                         displayed.
+       - 'no'          - Show no ignored files.
+       - 'matching'    - Shows ignored files and directories matching an
+                         ignore pattern.
++
+When 'matching' mode is specified, paths that explicity match an
+ignored pattern are shown. If a directory matches an ignore pattern,
+then it is shown, but not paths contained in the ignored directory. If
+a directory does not match an ignore pattern, but all contents are
+ignored, then the directory is not shown, but all contents are shown.
 
 -z::
        Terminate entries with NUL, instead of LF.  This implies
index 177610e..02569d0 100644 (file)
@@ -40,7 +40,7 @@ beginning. It is always easier to squash a few commits together than
 to split one big commit into several.  Don't be afraid of making too
 small or imperfect steps along the way. You can always go back later
 and edit the commits with `git rebase --interactive` before you
-publish them.  You can use `git stash save --keep-index` to run the
+publish them.  You can use `git stash push --keep-index` to run the
 test suite independent of other uncommitted changes; see the EXAMPLES
 section of linkgit:git-stash[1].
 
index 2552ab8..3888c3f 100644 (file)
@@ -57,6 +57,16 @@ set to `no` at the beginning of them.
 With --no-log do not list one-line descriptions from the
 actual commits being merged.
 
+--signoff::
+--no-signoff::
+       Add Signed-off-by line by the committer at the end of the commit
+       log message.  The meaning of a signoff depends on the project,
+       but it typically certifies that committer has
+       the rights to submit this work under the same license and
+       agrees to a Developer Certificate of Origin
+       (see http://developercertificate.org/ for more information).
++
+With --no-signoff do not add a Signed-off-by line.
 
 --stat::
 -n::
index 6c77b49..7fae00f 100644 (file)
@@ -22,16 +22,20 @@ The notable options are:
 
 `flags`::
 
-       A bit-field of options (the `*IGNORED*` flags are mutually exclusive):
+       A bit-field of options:
 
 `DIR_SHOW_IGNORED`:::
 
-       Return just ignored files in `entries[]`, not untracked files.
+       Return just ignored files in `entries[]`, not untracked
+       files. This flag is mutually exclusive with
+       `DIR_SHOW_IGNORED_TOO`.
 
 `DIR_SHOW_IGNORED_TOO`:::
 
-       Similar to `DIR_SHOW_IGNORED`, but return ignored files in `ignored[]`
-       in addition to untracked files in `entries[]`.
+       Similar to `DIR_SHOW_IGNORED`, but return ignored files in
+       `ignored[]` in addition to untracked files in
+       `entries[]`. This flag is mutually exclusive with
+       `DIR_SHOW_IGNORED`.
 
 `DIR_KEEP_UNTRACKED_CONTENTS`:::
 
@@ -39,6 +43,21 @@ The notable options are:
        untracked contents of untracked directories are also returned in
        `entries[]`.
 
+`DIR_SHOW_IGNORED_TOO_MODE_MATCHING`:::
+
+       Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if
+       this is set, returns ignored files and directories that match
+       an exclude pattern. If a directory matches an exclude pattern,
+       then the directory is returned and the contained paths are
+       not. A directory that does not match an exclude pattern will
+       not be returned even if all of its contents are ignored. In
+       this case, the contents are returned as individual entries.
++
+If this is set, files and directories that explicity match an ignore
+pattern are reported. Implicity ignored directories (directories that
+do not match an ignore pattern, but whose contents are all ignored)
+are not reported, instead all of the contents are reported.
+
 `DIR_COLLECT_IGNORED`:::
 
        Special mode for git-add. Return ignored files in `ignored[]` and
index b4d88af..3a03e63 100644 (file)
@@ -1556,7 +1556,7 @@ so on a different branch and then coming back), unstash the
 work-in-progress changes.
 
 ------------------------------------------------
-$ git stash save "work in progress for foo feature"
+$ git stash push -m "work in progress for foo feature"
 ------------------------------------------------
 
 This command will save your changes away to the `stash`, and
index 879178c..c1906f0 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.15.1
+DEF_VER=v2.15.GIT
 
 LF='
 '
index 0c1dd02..bec73d6 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.15.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.16.0.txt
\ No newline at end of file
index d81e1cb..c6169bc 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -17,6 +17,7 @@ int advice_set_upstream_failure = 1;
 int advice_object_name_warning = 1;
 int advice_rm_hints = 1;
 int advice_add_embedded_repo = 1;
+int advice_ignored_hook = 1;
 
 static struct {
        const char *name;
@@ -38,6 +39,7 @@ static struct {
        { "objectnamewarning", &advice_object_name_warning },
        { "rmhints", &advice_rm_hints },
        { "addembeddedrepo", &advice_add_embedded_repo },
+       { "ignoredhook", &advice_ignored_hook },
 
        /* make this an alias for backward compatibility */
        { "pushnonfastforward", &advice_push_update_rejected }
index c84a445..f525d6f 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -19,6 +19,7 @@ extern int advice_set_upstream_failure;
 extern int advice_object_name_warning;
 extern int advice_rm_hints;
 extern int advice_add_embedded_repo;
+extern int advice_ignored_hook;
 
 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 c022af5..d676deb 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -75,13 +75,10 @@ static int parse_ignorewhitespace_option(struct apply_state *state,
 }
 
 int init_apply_state(struct apply_state *state,
-                    const char *prefix,
-                    struct lock_file *lock_file)
+                    const char *prefix)
 {
        memset(state, 0, sizeof(*state));
        state->prefix = prefix;
-       state->lock_file = lock_file;
-       state->newfd = -1;
        state->apply = 1;
        state->line_termination = '\n';
        state->p_value = 1;
@@ -146,8 +143,6 @@ int check_apply_state(struct apply_state *state, int force_apply)
        }
        if (state->check_index)
                state->unsafe_paths = 0;
-       if (!state->lock_file)
-               return error("BUG: state->lock_file should not be NULL");
 
        if (state->apply_verbosity <= verbosity_silent) {
                state->saved_error_routine = get_error_routine();
@@ -4709,13 +4704,13 @@ static int apply_patch(struct apply_state *state,
                state->apply = 0;
 
        state->update_index = state->check_index && state->apply;
-       if (state->update_index && state->newfd < 0) {
+       if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
                if (state->index_file)
-                       state->newfd = hold_lock_file_for_update(state->lock_file,
-                                                                state->index_file,
-                                                                LOCK_DIE_ON_ERROR);
+                       hold_lock_file_for_update(&state->lock_file,
+                                                 state->index_file,
+                                                 LOCK_DIE_ON_ERROR);
                else
-                       state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR);
+                       hold_locked_index(&state->lock_file, LOCK_DIE_ON_ERROR);
        }
 
        if (state->check_index && read_apply_cache(state) < 0) {
@@ -4911,22 +4906,18 @@ int apply_all_patches(struct apply_state *state,
        }
 
        if (state->update_index) {
-               res = write_locked_index(&the_index, state->lock_file, COMMIT_LOCK);
+               res = write_locked_index(&the_index, &state->lock_file, COMMIT_LOCK);
                if (res) {
                        error(_("Unable to write new index file"));
                        res = -128;
                        goto end;
                }
-               state->newfd = -1;
        }
 
        res = !!errs;
 
 end:
-       if (state->newfd >= 0) {
-               rollback_lock_file(state->lock_file);
-               state->newfd = -1;
-       }
+       rollback_lock_file(&state->lock_file);
 
        if (state->apply_verbosity <= verbosity_silent) {
                set_error_routine(state->saved_error_routine);
diff --git a/apply.h b/apply.h
index d9b3957..dc4a019 100644 (file)
--- a/apply.h
+++ b/apply.h
@@ -36,9 +36,8 @@ enum apply_verbosity {
 struct apply_state {
        const char *prefix;
 
-       /* These are lock_file related */
-       struct lock_file *lock_file;
-       int newfd;
+       /* Lock file */
+       struct lock_file lock_file;
 
        /* These control what gets looked at and modified */
        int apply; /* this is not a dry-run */
@@ -116,8 +115,7 @@ extern int apply_parse_options(int argc, const char **argv,
                               int *force_apply, int *options,
                               const char * const *apply_usage);
 extern int init_apply_state(struct apply_state *state,
-                           const char *prefix,
-                           struct lock_file *lock_file);
+                           const char *prefix);
 extern void clear_apply_state(struct apply_state *state);
 extern int check_apply_state(struct apply_state *state, int force_apply);
 
index 1e41f4b..0b7b62a 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -371,7 +371,7 @@ static void parse_treeish_arg(const char **argv,
                const char *colon = strchrnul(name, ':');
                int refnamelen = colon - name;
 
-               if (!dwim_ref(name, refnamelen, oid.hash, &ref))
+               if (!dwim_ref(name, refnamelen, &oid, &ref))
                        die("no such ref: %.*s", refnamelen, name);
                free(ref);
        }
index 96beeb5..0fca17c 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -226,10 +226,11 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
                add_name_decoration(DECORATION_NONE, buf.buf, obj);
 
                p->item = array[i].commit;
-               p = p->next;
+               if (i < cnt - 1)
+                       p = p->next;
        }
-       if (p)
-               p->next = NULL;
+       free_commit_list(p->next);
+       p->next = NULL;
        strbuf_release(&buf);
        free(array);
        return list;
@@ -360,28 +361,29 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                return best_bisection_sorted(list, nr);
 }
 
-struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all,
-                                         int find_all)
+void find_bisection(struct commit_list **commit_list, int *reaches,
+                   int *all, int find_all)
 {
        int nr, on_list;
-       struct commit_list *p, *best, *next, *last;
+       struct commit_list *list, *p, *best, *next, *last;
        int *weights;
 
-       show_list("bisection 2 entry", 0, 0, list);
+       show_list("bisection 2 entry", 0, 0, *commit_list);
 
        /*
         * Count the number of total and tree-changing items on the
         * list, while reversing the list.
         */
-       for (nr = on_list = 0, last = NULL, p = list;
+       for (nr = on_list = 0, last = NULL, p = *commit_list;
             p;
             p = next) {
                unsigned flags = p->item->object.flags;
 
                next = p->next;
-               if (flags & UNINTERESTING)
+               if (flags & UNINTERESTING) {
+                       free(p);
                        continue;
+               }
                p->next = last;
                last = p;
                if (!(flags & TREESAME))
@@ -397,12 +399,16 @@ struct commit_list *find_bisection(struct commit_list *list,
        /* Do the real work of finding bisection commit. */
        best = do_find_bisection(list, nr, weights, find_all);
        if (best) {
-               if (!find_all)
+               if (!find_all) {
+                       list->item = best->item;
+                       free_commit_list(list->next);
+                       best = list;
                        best->next = NULL;
+               }
                *reaches = weight(best);
        }
        free(weights);
-       return best;
+       *commit_list = best;
 }
 
 static int register_ref(const char *refname, const struct object_id *oid,
@@ -433,7 +439,12 @@ static int read_bisect_refs(void)
 
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
+static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
+static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
+static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct argv_array *array)
 {
@@ -685,11 +696,12 @@ static int bisect_checkout(const struct object_id *bisect_rev, int no_checkout)
        char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
 
        memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
-       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 
        argv_checkout[2] = bisect_rev_hex;
        if (no_checkout) {
-               update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        } else {
                int res;
                res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@@ -954,8 +966,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
 
        bisect_common(&revs);
 
-       revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                      !!skipped_revs.nr);
+       find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
        revs.commits = managed_skipped(revs.commits, &tried);
 
        if (!revs.commits) {
@@ -1044,3 +1055,40 @@ int estimate_bisect_steps(int all)
 
        return (e < 3 * x) ? n : n - 1;
 }
+
+static int mark_for_removal(const char *refname, const struct object_id *oid,
+                           int flag, void *cb_data)
+{
+       struct string_list *refs = cb_data;
+       char *ref = xstrfmt("refs/bisect%s", refname);
+       string_list_append(refs, ref);
+       return 0;
+}
+
+int bisect_clean_state(void)
+{
+       int result = 0;
+
+       /* There may be some refs packed during bisection */
+       struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
+       for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
+       string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
+       result = delete_refs("bisect: remove", &refs_for_removal, REF_NO_DEREF);
+       refs_for_removal.strdup_strings = 1;
+       string_list_clear(&refs_for_removal, 0);
+       unlink_or_warn(git_path_bisect_expected_rev());
+       unlink_or_warn(git_path_bisect_ancestors_ok());
+       unlink_or_warn(git_path_bisect_log());
+       unlink_or_warn(git_path_bisect_names());
+       unlink_or_warn(git_path_bisect_run());
+       unlink_or_warn(git_path_bisect_terms());
+       /* Cleanup head-name if it got left by an old version of git-bisect */
+       unlink_or_warn(git_path_head_name());
+       /*
+        * Cleanup BISECT_START last to support the --no-checkout option
+        * introduced in the commit 4796e823a.
+        */
+       unlink_or_warn(git_path_bisect_start());
+
+       return result;
+}
index acd12ef..a5d9248 100644 (file)
--- a/bisect.h
+++ b/bisect.h
@@ -1,9 +1,15 @@
 #ifndef BISECT_H
 #define BISECT_H
 
-extern struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all,
-                                         int find_all);
+/*
+ * Find bisection. If something is found, `reaches` will be the number of
+ * commits that the best commit reaches. `all` will be the count of
+ * non-SAMETREE commits. If nothing is found, `list` will be NULL.
+ * Otherwise, it will be either all non-SAMETREE commits or the single
+ * best commit, as chosen by `find_all`.
+ */
+extern void find_bisection(struct commit_list **list, int *reaches, int *all,
+                          int find_all);
 
 extern struct commit_list *filter_skipped(struct commit_list *list,
                                          struct commit_list **tried,
@@ -28,4 +34,6 @@ extern int estimate_bisect_steps(int all);
 
 extern void read_bisect_terms(const char **bad, const char **good);
 
+extern int bisect_clean_state(void);
+
 #endif
diff --git a/blame.c b/blame.c
index f575e9c..2893f3c 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -166,7 +166,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        commit->date = now;
        parent_tail = &commit->parents;
 
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
+       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
                die("no such ref: HEAD");
 
        parent_tail = append_parent(parent_tail, &head_oid);
@@ -209,7 +209,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
-                       if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
+                       if (opt->flags.allow_textconv &&
                            textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
                                strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
@@ -293,7 +293,7 @@ static void fill_origin_blob(struct diff_options *opt,
                unsigned long file_size;
 
                (*num_read_blob)++;
-               if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
+               if (opt->flags.allow_textconv &&
                    textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
                        ;
                else
@@ -541,7 +541,7 @@ static struct blame_origin *find_origin(struct commit *parent,
         * same and diff-tree is fairly efficient about this.
         */
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
+       diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = 0;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        paths[0] = origin->path;
@@ -615,7 +615,7 @@ static struct blame_origin *find_rename(struct commit *parent,
        int i;
 
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
+       diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = origin->path;
@@ -1238,7 +1238,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                return; /* nothing remains for this target */
 
        diff_setup(&diff_opts);
-       DIFF_OPT_SET(&diff_opts, RECURSIVE);
+       diff_opts.flags.recursive = 1;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 
        diff_setup_done(&diff_opts);
@@ -1253,7 +1253,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
        if ((opt & PICKAXE_BLAME_COPY_HARDEST)
            || ((opt & PICKAXE_BLAME_COPY_HARDER)
                && (!porigin || strcmp(target->path, porigin->path))))
-               DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
+               diff_opts.flags.find_copies_harder = 1;
 
        if (is_null_oid(&target->commit->object.oid))
                do_diff_cache(&parent->tree->object.oid, &diff_opts);
@@ -1262,7 +1262,7 @@ static void find_copy_in_parent(struct blame_scoreboard *sb,
                              &target->commit->tree->object.oid,
                              "", &diff_opts);
 
-       if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
+       if (!diff_opts.flags.find_copies_harder)
                diffcore_std(&diff_opts);
 
        do {
@@ -1689,7 +1689,7 @@ static struct commit *dwim_reverse_initial(struct rev_info *revs,
                return NULL;
 
        /* Do we have HEAD? */
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
+       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
                return NULL;
        head_commit = lookup_commit_reference_gently(&head_oid, 1);
        if (!head_commit)
@@ -1825,7 +1825,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
                if (fill_blob_sha1_and_mode(o))
                        die(_("no such path %s in %s"), path, final_commit_name);
 
-               if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
+               if (sb->revs->diffopt.flags.allow_textconv &&
                    textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
                                    &sb->final_buf_size))
                        ;
index 4377ce2..62f7b0d 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -264,7 +264,7 @@ void create_branch(const char *name, const char *start_name,
                die(_("Not a valid object name: '%s'."), start_name);
        }
 
-       switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) {
+       switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref)) {
        case 0:
                /* Not branching from any existing branch */
                if (explicit_tracking)
@@ -305,7 +305,7 @@ void create_branch(const char *name, const char *start_name,
                transaction = ref_transaction_begin(&err);
                if (!transaction ||
                    ref_transaction_update(transaction, ref.buf,
-                                          oid.hash, forcing ? NULL : null_sha1,
+                                          &oid, forcing ? NULL : &null_oid,
                                           0, msg, &err) ||
                    ref_transaction_commit(transaction, &err))
                        die("%s", err.buf);
index a648cf4..8d08e99 100644 (file)
@@ -116,7 +116,7 @@ int add_files_to_cache(const char *prefix,
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        rev.diffopt.format_callback_data = &data;
-       rev.diffopt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+       rev.diffopt.flags.override_submodule_config = 1;
        rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
        clear_pathspec(&rev.prune_data);
@@ -218,7 +218,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        argc = setup_revisions(argc, argv, &rev, NULL);
        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
        rev.diffopt.use_color = 0;
-       DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
+       rev.diffopt.flags.ignore_dirty_submodules = 1;
        out = open(file, O_CREAT | O_WRONLY, 0666);
        if (out < 0)
                die(_("Could not open '%s' for writing."), file);
index d7513f5..02853b3 100644 (file)
@@ -1068,8 +1068,8 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
        if (!get_oid("HEAD", &curr_head)) {
                write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
                if (!state->rebasing)
-                       update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
-                                       UPDATE_REFS_DIE_ON_ERR);
+                       update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
+                                  UPDATE_REFS_DIE_ON_ERR);
        } else {
                write_state_text(state, "abort-safety", "");
                if (!state->rebasing)
@@ -1134,11 +1134,11 @@ static const char *msgnum(const struct am_state *state)
  */
 static void refresh_and_write_cache(void)
 {
-       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+       struct lock_file lock_file = LOCK_INIT;
 
-       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        refresh_cache(REFRESH_QUIET);
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+       if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write index file"));
 }
 
@@ -1157,9 +1157,9 @@ static int index_has_changes(struct strbuf *sb)
                struct diff_options opt;
 
                diff_setup(&opt);
-               DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
+               opt.flags.exit_with_status = 1;
                if (!sb)
-                       DIFF_OPT_SET(&opt, QUICK);
+                       opt.flags.quick = 1;
                do_diff_cache(&head, &opt);
                diffcore_std(&opt);
                for (i = 0; sb && i < diff_queued_diff.nr; i++) {
@@ -1168,7 +1168,7 @@ static int index_has_changes(struct strbuf *sb)
                        strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);
                }
                diff_flush(&opt);
-               return DIFF_OPT_TST(&opt, HAS_CHANGES) != 0;
+               return opt.flags.has_changes != 0;
        } else {
                for (i = 0; sb && i < active_nr; i++) {
                        if (i)
@@ -1409,8 +1409,8 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
        rev_info.show_root_diff = 1;
        rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
        rev_info.no_commit_id = 1;
-       DIFF_OPT_SET(&rev_info.diffopt, BINARY);
-       DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);
+       rev_info.diffopt.flags.binary = 1;
+       rev_info.diffopt.flags.full_index = 1;
        rev_info.diffopt.use_color = 0;
        rev_info.diffopt.file = fp;
        rev_info.diffopt.close_file = 1;
@@ -1488,11 +1488,10 @@ static int run_apply(const struct am_state *state, const char *index_file)
        struct argv_array apply_opts = ARGV_ARRAY_INIT;
        struct apply_state apply_state;
        int res, opts_left;
-       static struct lock_file lock_file;
        int force_apply = 0;
        int options = 0;
 
-       if (init_apply_state(&apply_state, NULL, &lock_file))
+       if (init_apply_state(&apply_state, NULL))
                die("BUG: init_apply_state() failed");
 
        argv_array_push(&apply_opts, "apply");
@@ -1686,8 +1685,8 @@ static void do_commit(const struct am_state *state)
        strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
                        state->msg);
 
-       update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
-                       UPDATE_REFS_DIE_ON_ERR);
+       update_ref(sb.buf, "HEAD", &commit, old_oid, 0,
+                  UPDATE_REFS_DIE_ON_ERR);
 
        if (state->rebasing) {
                FILE *fp = xfopen(am_path(state, "rewritten"), "a");
@@ -1946,15 +1945,14 @@ next:
  */
 static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
 {
-       struct lock_file *lock_file;
+       struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree_desc t[2];
 
        if (parse_tree(head) || parse_tree(remote))
                return -1;
 
-       lock_file = xcalloc(1, sizeof(struct lock_file));
-       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 
        refresh_cache(REFRESH_QUIET);
 
@@ -1970,11 +1968,11 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
        init_tree_desc(&t[1], remote->buffer, remote->size);
 
        if (unpack_trees(2, t, &opts)) {
-               rollback_lock_file(lock_file);
+               rollback_lock_file(&lock_file);
                return -1;
        }
 
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+       if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
        return 0;
@@ -1986,15 +1984,14 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
  */
 static int merge_tree(struct tree *tree)
 {
-       struct lock_file *lock_file;
+       struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree_desc t[1];
 
        if (parse_tree(tree))
                return -1;
 
-       lock_file = xcalloc(1, sizeof(struct lock_file));
-       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
@@ -2005,11 +2002,11 @@ static int merge_tree(struct tree *tree)
        init_tree_desc(&t[0], tree->buffer, tree->size);
 
        if (unpack_trees(1, t, &opts)) {
-               rollback_lock_file(lock_file);
+               rollback_lock_file(&lock_file);
                return -1;
        }
 
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+       if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
        return 0;
@@ -2135,7 +2132,7 @@ static void am_abort(struct am_state *state)
 
        am_rerere_clear();
 
-       curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+       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);
@@ -2147,11 +2144,11 @@ static void am_abort(struct am_state *state)
        clean_index(&curr_head, &orig_head);
 
        if (has_orig_head)
-               update_ref_oid("am --abort", "HEAD", &orig_head,
-                               has_curr_head ? &curr_head : NULL, 0,
-                               UPDATE_REFS_DIE_ON_ERR);
+               update_ref("am --abort", "HEAD", &orig_head,
+                          has_curr_head ? &curr_head : NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        else if (curr_branch)
-               delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
+               delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
 
        free(curr_branch);
        am_destroy(state);
index 81b9a61..48d3989 100644 (file)
@@ -9,8 +9,6 @@ static const char * const apply_usage[] = {
        NULL
 };
 
-static struct lock_file lock_file;
-
 int cmd_apply(int argc, const char **argv, const char *prefix)
 {
        int force_apply = 0;
@@ -18,7 +16,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
        int ret;
        struct apply_state state;
 
-       if (init_apply_state(&state, prefix, &lock_file))
+       if (init_apply_state(&state, prefix))
                exit(128);
 
        argc = apply_parse_options(argc, argv,
index 3324229..4b5fadc 100644 (file)
 #include "cache.h"
 #include "parse-options.h"
 #include "bisect.h"
+#include "refs.h"
+
+static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 
 static const char * const git_bisect_helper_usage[] = {
        N_("git bisect--helper --next-all [--no-checkout]"),
+       N_("git bisect--helper --write-terms <bad_term> <good_term>"),
+       N_("git bisect--helper --bisect-clean-state"),
        NULL
 };
 
+/*
+ * Check whether the string `term` belongs to the set of strings
+ * included in the variable arguments.
+ */
+LAST_ARG_MUST_BE_NULL
+static int one_of(const char *term, ...)
+{
+       int res = 0;
+       va_list matches;
+       const char *match;
+
+       va_start(matches, term);
+       while (!res && (match = va_arg(matches, const char *)))
+               res = !strcmp(term, match);
+       va_end(matches);
+
+       return res;
+}
+
+static int check_term_format(const char *term, const char *orig_term)
+{
+       int res;
+       char *new_term = xstrfmt("refs/bisect/%s", term);
+
+       res = check_refname_format(new_term, 0);
+       free(new_term);
+
+       if (res)
+               return error(_("'%s' is not a valid term"), term);
+
+       if (one_of(term, "help", "start", "skip", "next", "reset",
+                       "visualize", "view", "replay", "log", "run", "terms", NULL))
+               return error(_("can't use the builtin command '%s' as a term"), term);
+
+       /*
+        * In theory, nothing prevents swapping completely good and bad,
+        * but this situation could be confusing and hasn't been tested
+        * enough. Forbid it for now.
+        */
+
+       if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
+                (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
+               return error(_("can't change the meaning of the term '%s'"), term);
+
+       return 0;
+}
+
+static int write_terms(const char *bad, const char *good)
+{
+       FILE *fp = NULL;
+       int res;
+
+       if (!strcmp(bad, good))
+               return error(_("please use two different terms"));
+
+       if (check_term_format(bad, "bad") || check_term_format(good, "good"))
+               return -1;
+
+       fp = fopen(git_path_bisect_terms(), "w");
+       if (!fp)
+               return error_errno(_("could not open the file BISECT_TERMS"));
+
+       res = fprintf(fp, "%s\n%s\n", bad, good);
+       res |= fclose(fp);
+       return (res < 0) ? -1 : 0;
+}
+
+static int is_expected_rev(const char *expected_hex)
+{
+       struct strbuf actual_hex = STRBUF_INIT;
+       int res = 0;
+       if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) {
+               strbuf_trim(&actual_hex);
+               res = !strcmp(actual_hex.buf, expected_hex);
+       }
+       strbuf_release(&actual_hex);
+       return res;
+}
+
+static void check_expected_revs(const char **revs, int rev_nr)
+{
+       int i;
+
+       for (i = 0; i < rev_nr; i++) {
+               if (!is_expected_rev(revs[i])) {
+                       unlink_or_warn(git_path_bisect_ancestors_ok());
+                       unlink_or_warn(git_path_bisect_expected_rev());
+               }
+       }
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-       int next_all = 0;
+       enum {
+               NEXT_ALL = 1,
+               WRITE_TERMS,
+               BISECT_CLEAN_STATE,
+               CHECK_EXPECTED_REVS
+       } cmdmode = 0;
        int no_checkout = 0;
        struct option options[] = {
-               OPT_BOOL(0, "next-all", &next_all,
-                        N_("perform 'git bisect next'")),
+               OPT_CMDMODE(0, "next-all", &cmdmode,
+                        N_("perform 'git bisect next'"), NEXT_ALL),
+               OPT_CMDMODE(0, "write-terms", &cmdmode,
+                        N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
+               OPT_CMDMODE(0, "bisect-clean-state", &cmdmode,
+                        N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
+               OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
+                        N_("check for expected revs"), CHECK_EXPECTED_REVS),
                OPT_BOOL(0, "no-checkout", &no_checkout,
                         N_("update BISECT_HEAD instead of checking out the current commit")),
                OPT_END()
@@ -23,9 +132,25 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options,
                             git_bisect_helper_usage, 0);
 
-       if (!next_all)
+       if (!cmdmode)
                usage_with_options(git_bisect_helper_usage, options);
 
-       /* next-all */
-       return bisect_next_all(prefix, no_checkout);
+       switch (cmdmode) {
+       case NEXT_ALL:
+               return bisect_next_all(prefix, no_checkout);
+       case WRITE_TERMS:
+               if (argc != 2)
+                       return error(_("--write-terms requires two arguments"));
+               return write_terms(argv[0], argv[1]);
+       case BISECT_CLEAN_STATE:
+               if (argc != 0)
+                       return error(_("--bisect-clean-state requires no arguments"));
+               return bisect_clean_state();
+       case CHECK_EXPECTED_REVS:
+               check_expected_revs(argv, argc);
+               return 0;
+       default:
+               return error("BUG: unknown subcommand '%d'", cmdmode);
+       }
+       return 0;
 }
index 67adaef..005f55a 100644 (file)
@@ -708,8 +708,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        git_config(git_blame_config, &output_option);
        init_revisions(&revs, NULL);
        revs.date_mode = blame_date_mode;
-       DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
-       DIFF_OPT_SET(&revs.diffopt, FOLLOW_RENAMES);
+       revs.diffopt.flags.allow_textconv = 1;
+       revs.diffopt.flags.follow_renames = 1;
 
        save_commit_buffer = 0;
        dashdash_pos = 0;
@@ -734,9 +734,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
        }
 parse_done:
-       no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES);
+       no_whole_file_rename = !revs.diffopt.flags.follow_renames;
        xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC;
-       DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
+       revs.diffopt.flags.follow_renames = 0;
        argc = parse_options_end(&ctx);
 
        if (incremental || (output_option & OUTPUT_PORCELAIN)) {
@@ -803,7 +803,7 @@ parse_done:
        }
        blame_date_width -= 1; /* strip the null */
 
-       if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
+       if (revs.diffopt.flags.find_copies_harder)
                opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
                        PICKAXE_BLAME_COPY_HARDER);
 
index 79dc918..33fd5fc 100644 (file)
@@ -125,7 +125,7 @@ static int branch_merged(int kind, const char *name,
                if (upstream &&
                    (reference_name = reference_name_to_free =
                     resolve_refdup(upstream, RESOLVE_REF_READING,
-                                   oid.hash, NULL)) != NULL)
+                                   &oid, NULL)) != NULL)
                        reference_rev = lookup_commit_reference(&oid);
        }
        if (!reference_rev)
@@ -241,7 +241,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                                        RESOLVE_REF_READING
                                        | RESOLVE_REF_NO_RECURSE
                                        | RESOLVE_REF_ALLOW_BAD_NAME,
-                                       oid.hash, &flags);
+                                       &oid, &flags);
                if (!target) {
                        error(remote_branch
                              ? _("remote-tracking branch '%s' not found.")
@@ -257,8 +257,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        goto next;
                }
 
-               if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : oid.hash,
-                              REF_NODEREF)) {
+               if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid,
+                              REF_NO_DEREF)) {
                        error(remote_branch
                              ? _("Error deleting remote-tracking branch '%s'")
                              : _("Error deleting branch '%s'"),
@@ -636,7 +636,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
        track = git_branch_track;
 
-       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
        if (!strcmp(head, "HEAD"))
index 39c8be0..b0e78b8 100644 (file)
@@ -129,8 +129,6 @@ static const char * const builtin_checkout_index_usage[] = {
        NULL
 };
 
-static struct lock_file lock_file;
-
 static int option_parse_stage(const struct option *opt,
                              const char *arg, int unset)
 {
@@ -150,7 +148,7 @@ static int option_parse_stage(const struct option *opt,
 int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 {
        int i;
-       int newfd = -1;
+       struct lock_file lock_file = LOCK_INIT;
        int all = 0;
        int read_from_stdin = 0;
        int prefix_length;
@@ -206,7 +204,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
        if (index_opt && !state.base_dir_len && !to_tempfile) {
                state.refresh_cache = 1;
                state.istate = &the_index;
-               newfd = hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+               hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        }
 
        /* Check out named files first */
@@ -251,7 +249,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
        if (all)
                checkout_all(prefix, prefix_length);
 
-       if (0 <= newfd &&
+       if (is_lock_file_locked(&lock_file) &&
            write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die("Unable to write new index file");
        return 0;
index fc4f8fd..7d8bcc3 100644 (file)
@@ -247,7 +247,7 @@ static int checkout_paths(const struct checkout_opts *opts,
        struct object_id rev;
        struct commit *head;
        int errs = 0;
-       struct lock_file *lock_file;
+       struct lock_file lock_file = LOCK_INIT;
 
        if (opts->track != BRANCH_TRACK_UNSPECIFIED)
                die(_("'%s' cannot be used with updating paths"), "--track");
@@ -275,9 +275,7 @@ static int checkout_paths(const struct checkout_opts *opts,
                return run_add_interactive(revision, "--patch=checkout",
                                           &opts->pathspec);
 
-       lock_file = xcalloc(1, sizeof(struct lock_file));
-
-       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache_preload(&opts->pathspec) < 0)
                return error(_("index file corrupt"));
 
@@ -376,10 +374,10 @@ static int checkout_paths(const struct checkout_opts *opts,
        }
        errs |= finish_delayed_checkout(&state);
 
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+       if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
-       read_ref_full("HEAD", 0, rev.hash, NULL);
+       read_ref_full("HEAD", 0, &rev, NULL);
        head = lookup_commit_reference_gently(&rev, 1);
 
        errs |= post_checkout_hook(head, head, 0);
@@ -472,9 +470,9 @@ static int merge_working_tree(const struct checkout_opts *opts,
                              int *writeout_error)
 {
        int ret;
-       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+       struct lock_file lock_file = LOCK_INIT;
 
-       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache_preload(NULL) < 0)
                return error(_("index file corrupt"));
 
@@ -591,7 +589,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
        if (!cache_tree_fully_valid(active_cache_tree))
                cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
 
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+       if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
        if (!opts->force && !opts->quiet)
@@ -664,8 +662,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
        if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
                /* Nothing to do. */
        } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
-               update_ref(msg.buf, "HEAD", new->commit->object.oid.hash, NULL,
-                          REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
+                          REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path &&
                            advice_detached_head && !opts->force_detach)
@@ -827,7 +825,7 @@ static int switch_branches(const struct checkout_opts *opts,
        struct object_id rev;
        int flag, writeout_error = 0;
        memset(&old, 0, sizeof(old));
-       old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
+       old.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
        if (old.path)
                old.commit = lookup_commit_reference_gently(&rev, 1);
        if (!(flag & REF_ISSYMREF))
@@ -1038,7 +1036,7 @@ static int parse_branchname_arg(int argc, const char **argv,
        setup_branch_path(new);
 
        if (!check_refname_format(new->path, 0) &&
-           !read_ref(new->path, branch_rev.hash))
+           !read_ref(new->path, &branch_rev))
                oidcpy(rev, &branch_rev);
        else
                new->path = NULL; /* not an existing branch */
@@ -1136,7 +1134,7 @@ static int checkout_branch(struct checkout_opts *opts,
                struct object_id rev;
                int flag;
 
-               if (!read_ref_full("HEAD", 0, rev.hash, &flag) &&
+               if (!read_ref_full("HEAD", 0, &rev, &flag) &&
                    (flag & REF_ISSYMREF) && is_null_oid(&rev))
                        return switch_unborn_to_new_branch(opts);
        }
index dbddd98..b228457 100644 (file)
@@ -588,7 +588,7 @@ static void write_remote_refs(const struct ref *local_refs)
        for (r = local_refs; r; r = r->next) {
                if (!r->peer_ref)
                        continue;
-               if (ref_transaction_create(t, r->peer_ref->name, r->old_oid.hash,
+               if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
                                           0, NULL, &err))
                        die("%s", err.buf);
        }
@@ -610,12 +610,12 @@ static void write_followtags(const struct ref *refs, const char *msg)
                        continue;
                if (!has_object_file(&ref->old_oid))
                        continue;
-               update_ref(msg, ref->name, ref->old_oid.hash,
-                          NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        }
 }
 
-static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
 {
        struct ref **rm = cb_data;
        struct ref *ref = *rm;
@@ -630,7 +630,7 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
        if (!ref)
                return -1;
 
-       hashcpy(sha1, ref->old_oid.hash);
+       oidcpy(oid, &ref->old_oid);
        *rm = ref->next;
        return 0;
 }
@@ -682,23 +682,23 @@ static void update_head(const struct ref *our, const struct ref *remote,
                if (create_symref("HEAD", our->name, NULL) < 0)
                        die(_("unable to update HEAD"));
                if (!option_bare) {
-                       update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0,
+                       update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
                                   UPDATE_REFS_DIE_ON_ERR);
                        install_branch_config(0, head, option_origin, our->name);
                }
        } else if (our) {
                struct commit *c = lookup_commit_reference(&our->old_oid);
                /* --branch specifies a non-branch (i.e. tags), detach HEAD */
-               update_ref(msg, "HEAD", c->object.oid.hash,
-                          NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
+                          UPDATE_REFS_DIE_ON_ERR);
        } else if (remote) {
                /*
                 * We know remote HEAD points to a non-branch, or
                 * HEAD points to a branch but we don't know which one.
                 * Detach HEAD in all these cases.
                 */
-               update_ref(msg, "HEAD", remote->old_oid.hash,
-                          NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
+                          UPDATE_REFS_DIE_ON_ERR);
        }
 }
 
@@ -706,7 +706,7 @@ static int checkout(int submodule_progress)
 {
        struct object_id oid;
        char *head;
-       struct lock_file *lock_file;
+       struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree *tree;
        struct tree_desc t;
@@ -715,7 +715,7 @@ static int checkout(int submodule_progress)
        if (option_no_checkout)
                return 0;
 
-       head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
+       head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
        if (!head) {
                warning(_("remote HEAD refers to nonexistent ref, "
                          "unable to checkout.\n"));
@@ -733,8 +733,7 @@ static int checkout(int submodule_progress)
        /* We need to be in the new work tree for the checkout */
        setup_work_tree();
 
-       lock_file = xcalloc(1, sizeof(struct lock_file));
-       hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 
        memset(&opts, 0, sizeof opts);
        opts.update = 1;
@@ -750,7 +749,7 @@ static int checkout(int submodule_progress)
        if (unpack_trees(1, &t, &opts) < 0)
                die(_("unable to checkout working tree"));
 
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+       if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
        err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
index b2a6c7f..8a87701 100644 (file)
@@ -118,7 +118,7 @@ static int edit_flag = -1; /* unspecified */
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int config_commit_verbose = -1; /* unspecified */
 static int no_post_rewrite, allow_empty_message;
-static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
+static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
 static char *sign_commit;
 
 /*
@@ -139,7 +139,7 @@ static const char *cleanup_arg;
 static enum commit_whence whence;
 static int sequencer_in_use;
 static int use_editor = 1, include_status = 1;
-static int show_ignored_in_status, have_option_m;
+static int have_option_m;
 static struct strbuf message = STRBUF_INIT;
 
 static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
@@ -355,7 +355,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
 
                refresh_cache_or_die(refresh_flags);
 
-               if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+               if (write_locked_index(&the_index, &index_lock, 0))
                        die(_("unable to create temporary index"));
 
                old_index_env = getenv(INDEX_ENVIRONMENT);
@@ -374,7 +374,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
                        if (reopen_lock_file(&index_lock) < 0)
                                die(_("unable to write index file"));
-                       if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+                       if (write_locked_index(&the_index, &index_lock, 0))
                                die(_("unable to update temporary index"));
                } else
                        warning(_("Failed to update main cache tree"));
@@ -401,7 +401,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                update_main_cache_tree(WRITE_TREE_SILENT);
-               if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+               if (write_locked_index(&the_index, &index_lock, 0))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
                ret = get_lock_file_path(&index_lock);
@@ -474,7 +474,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
        update_main_cache_tree(WRITE_TREE_SILENT);
-       if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+       if (write_locked_index(&the_index, &index_lock, 0))
                die(_("unable to write new_index file"));
 
        hold_lock_file_for_update(&false_lock,
@@ -486,7 +486,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
 
-       if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK))
+       if (write_locked_index(&the_index, &false_lock, 0))
                die(_("unable to write temporary index file"));
 
        discard_cache();
@@ -912,11 +912,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                         * submodules which were manually staged, which would
                         * be really confusing.
                         */
-                       int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+                       struct diff_flags flags = DIFF_FLAGS_INIT;
+                       flags.override_submodule_config = 1;
                        if (ignore_submodule_arg &&
                            !strcmp(ignore_submodule_arg, "all"))
-                               diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
-                       commitable = index_differs_from(parent, diff_flags, 1);
+                               flags.ignore_submodules = 1;
+                       commitable = index_differs_from(parent, &flags, 1);
                }
        }
        strbuf_release(&committer_ident);
@@ -1075,6 +1076,19 @@ static const char *find_author_by_nickname(const char *name)
        die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
 }
 
+static void handle_ignored_arg(struct wt_status *s)
+{
+       if (!ignored_arg)
+               ; /* default already initialized */
+       else if (!strcmp(ignored_arg, "traditional"))
+               s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED;
+       else if (!strcmp(ignored_arg, "no"))
+               s->show_ignored_mode = SHOW_NO_IGNORED;
+       else if (!strcmp(ignored_arg, "matching"))
+               s->show_ignored_mode = SHOW_MATCHING_IGNORED;
+       else
+               die(_("Invalid ignored mode '%s'"), ignored_arg);
+}
 
 static void handle_untracked_files_arg(struct wt_status *s)
 {
@@ -1363,8 +1377,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                  N_("mode"),
                  N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
-               OPT_BOOL(0, "ignored", &show_ignored_in_status,
-                        N_("show ignored files")),
+               { OPTION_STRING, 0, "ignored", &ignored_arg,
+                 N_("mode"),
+                 N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
+                 PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" },
                { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
                  N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
@@ -1383,8 +1399,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        finalize_deferred_config(&s);
 
        handle_untracked_files_arg(&s);
-       if (show_ignored_in_status)
-               s.show_ignored_files = 1;
+       handle_ignored_arg(&s);
+
+       if (s.show_ignored_mode == SHOW_MATCHING_IGNORED &&
+           s.show_untracked_files == SHOW_NO_UNTRACKED_FILES)
+               die(_("Unsupported combination of ignored and untracked-files arguments"));
+
        parse_pathspec(&s.pathspec, 0,
                       PATHSPEC_PREFER_FULL,
                       prefix, argv);
@@ -1730,7 +1750,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                                allow_fast_forward = 0;
                }
                if (allow_fast_forward)
-                       parents = reduce_heads(parents);
+                       reduce_heads_replace(&parents);
        } else {
                if (!reflog_msg)
                        reflog_msg = (whence == FROM_CHERRY_PICK)
@@ -1790,9 +1810,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, "HEAD", oid.hash,
+           ref_transaction_update(transaction, "HEAD", &oid,
                                   current_head
-                                  ? current_head->object.oid.hash : null_sha1,
+                                  ? &current_head->object.oid : &null_oid,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
index 29075db..e14e162 100644 (file)
@@ -7,12 +7,12 @@
 #include "builtin.h"
 #include "exec_cmd.h"
 #include "parse-options.h"
+#include "revision.h"
 #include "diff.h"
 #include "hashmap.h"
 #include "argv-array.h"
 #include "run-command.h"
 
-#define SEEN           (1u << 0)
 #define MAX_TAGS       (FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
@@ -181,7 +181,7 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
        }
 
        /* Is it annotated? */
-       if (!peel_ref(path, peeled.hash)) {
+       if (!peel_ref(path, &peeled)) {
                is_annotated = !!oidcmp(oid, &peeled);
        } else {
                oidcpy(&peeled, oid);
@@ -543,7 +543,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        }
                } else if (dirty) {
                        static struct lock_file index_lock;
-                       int fd;
+                       struct rev_info revs;
+                       struct argv_array args = ARGV_ARRAY_INIT;
+                       int fd, result;
 
                        read_cache_preload(NULL);
                        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
@@ -552,8 +554,13 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        if (0 <= fd)
                                update_index_if_able(&the_index, &index_lock);
 
-                       if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
-                                           diff_index_args, prefix))
+                       init_revisions(&revs, prefix);
+                       argv_array_pushv(&args, diff_index_args);
+                       if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
+                               BUG("malformed internal diff-index command line");
+                       result = run_diff_index(&revs, 0);
+
+                       if (!diff_result_code(&revs.diffopt, result))
                                suffix = NULL;
                        else
                                suffix = dirty;
index f5bbd4d..9808d06 100644 (file)
@@ -44,7 +44,7 @@ static void stuff_change(struct diff_options *opt,
            !oidcmp(old_oid, new_oid) && (old_mode == new_mode))
                return;
 
-       if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
+       if (opt->flags.reverse_diff) {
                SWAP(old_mode, new_mode);
                SWAP(old_oid, new_oid);
                SWAP(old_path, new_path);
@@ -203,17 +203,16 @@ static int builtin_diff_combined(struct rev_info *revs,
 
 static void refresh_index_quietly(void)
 {
-       struct lock_file *lock_file;
+       struct lock_file lock_file = LOCK_INIT;
        int fd;
 
-       lock_file = xcalloc(1, sizeof(struct lock_file));
-       fd = hold_locked_index(lock_file, 0);
+       fd = hold_locked_index(&lock_file, 0);
        if (fd < 0)
                return;
        discard_cache();
        read_cache();
        refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
-       update_index_if_able(&the_index, lock_file);
+       update_index_if_able(&the_index, &lock_file);
 }
 
 static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
@@ -350,8 +349,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        rev.diffopt.stat_graph_width = -1;
 
        /* Default to let external and textconv be used */
-       DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
-       DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
+       rev.diffopt.flags.allow_external = 1;
+       rev.diffopt.flags.allow_textconv = 1;
 
        if (nongit)
                die(_("Not a git repository"));
@@ -361,7 +360,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                diff_setup_done(&rev.diffopt);
        }
 
-       DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+       rev.diffopt.flags.recursive = 1;
 
        setup_diff_pager(&rev.diffopt);
 
index b2d3ba7..bcc79d1 100644 (file)
@@ -616,7 +616,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
                        if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
                            write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
                                ret = error("could not write %s", buf.buf);
-                               rollback_lock_file(&lock);
                                goto finish;
                        }
                        changed_files(&wt_modified, buf.buf, workdir);
index 2fb60d6..f8fe04c 100644 (file)
@@ -823,7 +823,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
                if (e->flags & UNINTERESTING)
                        continue;
 
-               if (dwim_ref(e->name, strlen(e->name), oid.hash, &full_name) != 1)
+               if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
                        continue;
 
                if (refspecs) {
@@ -1066,7 +1066,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                die("revision walk setup failed");
        revs.diffopt.format_callback = show_filemodify;
        revs.diffopt.format_callback_data = &paths_of_changed_objects;
-       DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+       revs.diffopt.flags.recursive = 1;
        while ((commit = get_revision(&revs))) {
                if (has_unshown_parent(commit)) {
                        add_object_array(&commit->object, NULL, &commits);
index 225c734..e705237 100644 (file)
@@ -457,8 +457,8 @@ static int s_update_ref(const char *action,
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, ref->name,
-                                  ref->new_oid.hash,
-                                  check_old ? ref->old_oid.hash : NULL,
+                                  &ref->new_oid,
+                                  check_old ? &ref->old_oid : NULL,
                                   0, msg, &err))
                goto fail;
 
@@ -727,7 +727,7 @@ static int update_local_ref(struct ref *ref,
        }
 }
 
-static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
 {
        struct ref **rm = cb_data;
        struct ref *ref = *rm;
@@ -737,7 +737,7 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
        if (!ref)
                return -1; /* end of the list */
        *rm = ref->next;
-       hashcpy(sha1, ref->old_oid.hash);
+       oidcpy(oid, &ref->old_oid);
        return 0;
 }
 
index e99b5dd..22034f8 100644 (file)
@@ -571,7 +571,7 @@ static void find_merge_parents(struct merge_parents *result,
        head_commit = lookup_commit(head);
        if (head_commit)
                commit_list_insert(head_commit, &parents);
-       parents = reduce_heads(parents);
+       reduce_heads_replace(&parents);
 
        while (parents) {
                struct commit *cmit = pop_commit(&parents);
@@ -603,7 +603,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 
        /* get current branch */
        current_branch = current_branch_to_free =
-               resolve_refdup("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL);
+               resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL);
        if (!current_branch)
                die("No current branch");
        if (starts_with(current_branch, "refs/heads/"))
index 56afe40..04846d4 100644 (file)
@@ -555,7 +555,7 @@ static int fsck_head_link(void)
        if (verbose)
                fprintf(stderr, "Checking HEAD link\n");
 
-       head_points_at = resolve_ref_unsafe("HEAD", 0, head_oid.hash, NULL);
+       head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL);
        if (!head_points_at) {
                errors_found |= ERROR_REFS;
                return error("Invalid HEAD");
@@ -759,6 +759,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 
        if (keep_cache_objects) {
                verify_index_checksum = 1;
+               verify_ce_order = 1;
                read_cache();
                for (i = 0; i < active_nr; i++) {
                        unsigned int mode;
index d81a090..6c1fa89 100644 (file)
@@ -121,20 +121,19 @@ static void cmd_log_init_defaults(struct rev_info *rev)
        if (fmt_pretty)
                get_commit_format(fmt_pretty, rev);
        if (default_follow)
-               DIFF_OPT_SET(&rev->diffopt, DEFAULT_FOLLOW_RENAMES);
+               rev->diffopt.flags.default_follow_renames = 1;
        rev->verbose_header = 1;
-       DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
+       rev->diffopt.flags.recursive = 1;
        rev->diffopt.stat_width = -1; /* use full terminal width */
        rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
        rev->abbrev_commit = default_abbrev_commit;
        rev->show_root_diff = default_show_root;
        rev->subject_prefix = fmt_patch_subject_prefix;
        rev->show_signature = default_show_signature;
-       DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
+       rev->diffopt.flags.allow_textconv = 1;
 
        if (default_date_mode)
                parse_date_format(default_date_mode, &rev->date_mode);
-       rev->diffopt.touched_flags = 0;
 }
 
 static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
@@ -182,7 +181,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                init_display_notes(&rev->notes_opt);
 
        if (rev->diffopt.pickaxe || rev->diffopt.filter ||
-           DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES))
+           rev->diffopt.flags.follow_renames)
                rev->always_show_header = 0;
 
        if (source)
@@ -392,7 +391,7 @@ static int cmd_log_walk(struct rev_info *rev)
                fclose(rev->diffopt.file);
 
        if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
-           DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
+           rev->diffopt.flags.check_failed) {
                return 02;
        }
        return diff_result_code(&rev->diffopt, 0);
@@ -484,8 +483,8 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
        unsigned long size;
 
        fflush(rev->diffopt.file);
-       if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
-           !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
+       if (!rev->diffopt.flags.textconv_set_via_cmdline ||
+           !rev->diffopt.flags.allow_textconv)
                return stream_blob_to_fd(1, oid, NULL, 0);
 
        if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
@@ -667,9 +666,9 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
 static void log_setup_revisions_tweak(struct rev_info *rev,
                                      struct setup_revision_opt *opt)
 {
-       if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
+       if (rev->diffopt.flags.default_follow_renames &&
            rev->prune_data.nr == 1)
-               DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);
+               rev->diffopt.flags.follow_renames = 1;
 
        /* Turn --cc/-c into -p --cc/-c when -p was not given */
        if (!rev->diffopt.output_format && rev->combine_merges)
@@ -975,7 +974,7 @@ static char *find_branch_name(struct rev_info *rev)
                return NULL;
        ref = rev->cmdline.rev[positive].name;
        tip_oid = &rev->cmdline.rev[positive].item->oid;
-       if (dwim_ref(ref, strlen(ref), branch_oid.hash, &full_ref) &&
+       if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
            skip_prefix(full_ref, "refs/heads/", &v) &&
            !oidcmp(tip_oid, &branch_oid))
                branch = xstrdup(v);
@@ -1341,7 +1340,7 @@ static void prepare_bases(struct base_tree_info *bases,
                return;
 
        diff_setup(&diffopt);
-       DIFF_OPT_SET(&diffopt, RECURSIVE);
+       diffopt.flags.recursive = 1;
        diff_setup_done(&diffopt);
 
        oidcpy(&bases->base_commit, &base->object.oid);
@@ -1512,7 +1511,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.verbose_header = 1;
        rev.diff = 1;
        rev.max_parents = 1;
-       DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+       rev.diffopt.flags.recursive = 1;
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
        s_r_opt.def = "HEAD";
@@ -1613,8 +1612,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
        rev.zero_commit = zero_commit;
 
-       if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
-               DIFF_OPT_SET(&rev.diffopt, BINARY);
+       if (!rev.diffopt.flags.text && !no_binary_diff)
+               rev.diffopt.flags.binary = 1;
 
        if (rev.show_notes)
                init_display_notes(&rev.notes_opt);
index 6dbd167..3b76001 100644 (file)
@@ -9,20 +9,20 @@
 
 static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 {
-       struct commit_list *result;
+       struct commit_list *result, *r;
 
        result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
 
        if (!result)
                return 1;
 
-       while (result) {
-               printf("%s\n", oid_to_hex(&result->item->object.oid));
+       for (r = result; r; r = r->next) {
+               printf("%s\n", oid_to_hex(&r->item->object.oid));
                if (!show_all)
-                       return 0;
-               result = result->next;
+                       break;
        }
 
+       free_commit_list(result);
        return 0;
 }
 
@@ -51,45 +51,47 @@ static struct commit *get_commit_reference(const char *arg)
 
 static int handle_independent(int count, const char **args)
 {
-       struct commit_list *revs = NULL;
-       struct commit_list *result;
+       struct commit_list *revs = NULL, *rev;
        int i;
 
        for (i = count - 1; i >= 0; i--)
                commit_list_insert(get_commit_reference(args[i]), &revs);
 
-       result = reduce_heads(revs);
-       if (!result)
+       reduce_heads_replace(&revs);
+
+       if (!revs)
                return 1;
 
-       while (result) {
-               printf("%s\n", oid_to_hex(&result->item->object.oid));
-               result = result->next;
-       }
+       for (rev = revs; rev; rev = rev->next)
+               printf("%s\n", oid_to_hex(&rev->item->object.oid));
+
+       free_commit_list(revs);
        return 0;
 }
 
 static int handle_octopus(int count, const char **args, int show_all)
 {
        struct commit_list *revs = NULL;
-       struct commit_list *result;
+       struct commit_list *result, *rev;
        int i;
 
        for (i = count - 1; i >= 0; i--)
                commit_list_insert(get_commit_reference(args[i]), &revs);
 
-       result = reduce_heads(get_octopus_merge_bases(revs));
+       result = get_octopus_merge_bases(revs);
+       free_commit_list(revs);
+       reduce_heads_replace(&result);
 
        if (!result)
                return 1;
 
-       while (result) {
-               printf("%s\n", oid_to_hex(&result->item->object.oid));
+       for (rev = result; rev; rev = rev->next) {
+               printf("%s\n", oid_to_hex(&rev->item->object.oid));
                if (!show_all)
-                       return 0;
-               result = result->next;
+                       break;
        }
 
+       free_commit_list(result);
        return 0;
 }
 
@@ -156,7 +158,7 @@ static int handle_fork_point(int argc, const char **argv)
        struct commit_list *bases;
        int i, ret = 0;
 
-       switch (dwim_ref(argv[0], strlen(argv[0]), oid.hash, &refname)) {
+       switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
        case 0:
                die("No such ref: '%s'", argv[0]);
        case 1:
index 6844116..c84c6e0 100644 (file)
@@ -9,26 +9,24 @@
  */
 #include "git-compat-util.h"
 #include "builtin.h"
+#include "diff.h"
 
 static const char builtin_merge_ours_usage[] =
        "git merge-ours <base>... -- HEAD <remote>...";
 
-static const char *diff_index_args[] = {
-       "diff-index", "--quiet", "--cached", "HEAD", "--", NULL
-};
-#define NARGS (ARRAY_SIZE(diff_index_args) - 1)
-
 int cmd_merge_ours(int argc, const char **argv, const char *prefix)
 {
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(builtin_merge_ours_usage);
 
        /*
-        * We need to exit with 2 if the index does not match our HEAD tree,
-        * because the current index is what we will be committing as the
-        * merge result.
+        * The contents of the current index becomes the tree we
+        * commit.  The index must match HEAD, or this merge cannot go
+        * through.
         */
-       if (cmd_diff_index(NARGS, diff_index_args, prefix))
+       if (read_cache() < 0)
+               die_errno("read_cache failed");
+       if (index_differs_from("HEAD", NULL, 0))
                exit(2);
        exit(0);
 }
index ab5ffe8..612dd7b 100644 (file)
@@ -405,9 +405,8 @@ static void finish(struct commit *head_commit,
                        printf(_("No merge message -- not updating HEAD\n"));
                else {
                        const char *argv_gc_auto[] = { "gc", "--auto", NULL };
-                       update_ref(reflog_message.buf, "HEAD",
-                               new_head->hash, head->hash, 0,
-                               UPDATE_REFS_DIE_ON_ERR);
+                       update_ref(reflog_message.buf, "HEAD", new_head, head,
+                                  0, UPDATE_REFS_DIE_ON_ERR);
                        /*
                         * We ignore errors in 'gc --auto', since the
                         * user should see them.
@@ -455,7 +454,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
        if (!remote_head)
                die(_("'%s' does not point to a commit"), remote);
 
-       if (dwim_ref(remote, strlen(remote), branch_head.hash, &found_ref) > 0) {
+       if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref) > 0) {
                if (starts_with(found_ref, "refs/heads/")) {
                        strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
                                    oid_to_hex(&branch_head), remote);
@@ -999,6 +998,7 @@ static struct commit_list *reduce_parents(struct commit *head_commit,
 
        /* Find what parents to record by checking independent ones. */
        parents = reduce_heads(remoteheads);
+       free_commit_list(remoteheads);
 
        remoteheads = NULL;
        remotes = &remoteheads;
@@ -1143,7 +1143,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
         * current branch.
         */
-       branch = branch_to_free = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (branch)
                skip_prefix(branch, "refs/heads/", &branch);
        if (!branch || is_null_oid(&head_oid))
@@ -1261,8 +1261,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        die(_("Can merge only exactly one commit into empty head"));
                remote_head_oid = &remoteheads->item->object.oid;
                read_empty(remote_head_oid->hash, 0);
-               update_ref("initial pull", "HEAD", remote_head_oid->hash,
-                          NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
                goto done;
        }
 
@@ -1357,8 +1357,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                free(list);
        }
 
-       update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.oid.hash,
-                  NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+       update_ref("updating ORIG_HEAD", "ORIG_HEAD",
+                  &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 
        if (remoteheads && !common) {
                /* No common ancestors found. */
index 8e54f2d..d7754db 100644 (file)
@@ -686,7 +686,7 @@ static int merge_abort(struct notes_merge_options *o)
 
        if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
                ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
-       if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NODEREF))
+       if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
                ret += error(_("failed to delete ref NOTES_MERGE_REF"));
        if (notes_merge_abort(o))
                ret += error(_("failed to remove 'git notes merge' worktree"));
@@ -724,7 +724,7 @@ static int merge_commit(struct notes_merge_options *o)
        init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
        o->local_ref = local_ref_to_free =
-               resolve_refdup("NOTES_MERGE_REF", 0, oid.hash, NULL);
+               resolve_refdup("NOTES_MERGE_REF", 0, &oid, NULL);
        if (!o->local_ref)
                die(_("failed to resolve NOTES_MERGE_REF"));
 
@@ -736,8 +736,8 @@ static int merge_commit(struct notes_merge_options *o)
        format_commit_message(partial, "%s", &msg, &pretty_ctx);
        strbuf_trim(&msg);
        strbuf_insert(&msg, 0, "notes: ", 7);
-       update_ref(msg.buf, o->local_ref, oid.hash,
-                  is_null_oid(&parent_oid) ? NULL : parent_oid.hash,
+       update_ref(msg.buf, o->local_ref, &oid,
+                  is_null_oid(&parent_oid) ? NULL : &parent_oid,
                   0, UPDATE_REFS_DIE_ON_ERR);
 
        free_notes(t);
@@ -850,12 +850,12 @@ static int merge(int argc, const char **argv, const char *prefix)
 
        if (result >= 0) /* Merge resulted (trivially) in result_oid */
                /* Update default notes ref with new commit */
-               update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL,
-                          0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        else { /* Merge has unresolved conflicts */
                const struct worktree *wt;
                /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
-               update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL,
+               update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL,
                           0, UPDATE_REFS_DIE_ON_ERR);
                /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
                wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
index 6e77dfd..631de28 100644 (file)
@@ -151,7 +151,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)
 }
 
 static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
-                                          const unsigned char *sha1)
+                                          const struct object_id *oid)
 {
        git_zstream stream;
        unsigned char ibuf[1024 * 16];
@@ -165,7 +165,7 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi
                int zret = Z_OK;
                readlen = read_istream(st, ibuf, sizeof(ibuf));
                if (readlen == -1)
-                       die(_("unable to read %s"), sha1_to_hex(sha1));
+                       die(_("unable to read %s"), oid_to_hex(oid));
 
                stream.next_in = ibuf;
                stream.avail_in = readlen;
@@ -339,7 +339,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                sha1write(f, header, hdrlen);
        }
        if (st) {
-               datalen = write_large_blob_data(st, f, entry->idx.oid.hash);
+               datalen = write_large_blob_data(st, f, &entry->idx.oid);
                close_istream(st);
        } else {
                sha1write(f, buf, datalen);
@@ -557,13 +557,13 @@ static enum write_one_status write_one(struct sha1file *f,
 static int mark_tagged(const char *path, const struct object_id *oid, int flag,
                       void *cb_data)
 {
-       unsigned char peeled[20];
+       struct object_id peeled;
        struct object_entry *entry = packlist_find(&to_pack, oid->hash, NULL);
 
        if (entry)
                entry->tagged = 1;
-       if (!peel_ref(path, peeled)) {
-               entry = packlist_find(&to_pack, peeled, NULL);
+       if (!peel_ref(path, &peeled)) {
+               entry = packlist_find(&to_pack, peeled.hash, NULL);
                if (entry)
                        entry->tagged = 1;
        }
@@ -792,7 +792,7 @@ static void write_pack_file(void)
        write_order = compute_write_order();
 
        do {
-               unsigned char sha1[20];
+               struct object_id oid;
                char *pack_tmp_name = NULL;
 
                if (pack_to_stdout)
@@ -823,13 +823,13 @@ static void write_pack_file(void)
                 * If so, rewrite it like in fast-import
                 */
                if (pack_to_stdout) {
-                       sha1close(f, sha1, CSUM_CLOSE);
+                       sha1close(f, oid.hash, CSUM_CLOSE);
                } else if (nr_written == nr_remaining) {
-                       sha1close(f, sha1, CSUM_FSYNC);
+                       sha1close(f, oid.hash, CSUM_FSYNC);
                } else {
-                       int fd = sha1close(f, sha1, 0);
-                       fixup_pack_header_footer(fd, sha1, pack_tmp_name,
-                                                nr_written, sha1, offset);
+                       int fd = sha1close(f, oid.hash, 0);
+                       fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
+                                                nr_written, oid.hash, offset);
                        close(fd);
                        if (write_bitmap_index) {
                                warning(_(no_split_warning));
@@ -863,16 +863,16 @@ static void write_pack_file(void)
                        strbuf_addf(&tmpname, "%s-", base_name);
 
                        if (write_bitmap_index) {
-                               bitmap_writer_set_checksum(sha1);
+                               bitmap_writer_set_checksum(oid.hash);
                                bitmap_writer_build_type_index(written_list, nr_written);
                        }
 
                        finish_tmp_packfile(&tmpname, pack_tmp_name,
                                            written_list, nr_written,
-                                           &pack_idx_opts, sha1);
+                                           &pack_idx_opts, oid.hash);
 
                        if (write_bitmap_index) {
-                               strbuf_addf(&tmpname, "%s.bitmap", sha1_to_hex(sha1));
+                               strbuf_addf(&tmpname, "%s.bitmap", oid_to_hex(&oid));
 
                                stop_progress(&progress_state);
 
@@ -887,7 +887,7 @@ static void write_pack_file(void)
 
                        strbuf_release(&tmpname);
                        free(pack_tmp_name);
-                       puts(sha1_to_hex(sha1));
+                       puts(oid_to_hex(&oid));
                }
 
                /* mark written objects as written to previous pack */
@@ -928,13 +928,13 @@ static int no_try_delta(const char *path)
  * found the item, since that saves us from having to look it up again a
  * few lines later when we want to add the new entry.
  */
-static int have_duplicate_entry(const unsigned char *sha1,
+static int have_duplicate_entry(const struct object_id *oid,
                                int exclude,
                                uint32_t *index_pos)
 {
        struct object_entry *entry;
 
-       entry = packlist_find(&to_pack, sha1, index_pos);
+       entry = packlist_find(&to_pack, oid->hash, index_pos);
        if (!entry)
                return 0;
 
@@ -990,7 +990,7 @@ static int want_found_object(int exclude, struct packed_git *p)
  * function finds if there is any pack that has the object and returns the pack
  * and its offset in these variables.
  */
-static int want_object_in_pack(const unsigned char *sha1,
+static int want_object_in_pack(const struct object_id *oid,
                               int exclude,
                               struct packed_git **found_pack,
                               off_t *found_offset)
@@ -998,7 +998,7 @@ static int want_object_in_pack(const unsigned char *sha1,
        struct mru_entry *entry;
        int want;
 
-       if (!exclude && local && has_loose_object_nonlocal(sha1))
+       if (!exclude && local && has_loose_object_nonlocal(oid->hash))
                return 0;
 
        /*
@@ -1019,7 +1019,7 @@ static int want_object_in_pack(const unsigned char *sha1,
                if (p == *found_pack)
                        offset = *found_offset;
                else
-                       offset = find_pack_entry_one(sha1, p);
+                       offset = find_pack_entry_one(oid->hash, p);
 
                if (offset) {
                        if (!*found_pack) {
@@ -1039,7 +1039,7 @@ static int want_object_in_pack(const unsigned char *sha1,
        return 1;
 }
 
-static void create_object_entry(const unsigned char *sha1,
+static void create_object_entry(const struct object_id *oid,
                                enum object_type type,
                                uint32_t hash,
                                int exclude,
@@ -1050,7 +1050,7 @@ static void create_object_entry(const unsigned char *sha1,
 {
        struct object_entry *entry;
 
-       entry = packlist_alloc(&to_pack, sha1, index_pos);
+       entry = packlist_alloc(&to_pack, oid->hash, index_pos);
        entry->hash = hash;
        if (type)
                entry->type = type;
@@ -1070,17 +1070,17 @@ static const char no_closure_warning[] = N_(
 "disabling bitmap writing, as some objects are not being packed"
 );
 
-static int add_object_entry(const unsigned char *sha1, enum object_type type,
+static int add_object_entry(const struct object_id *oid, enum object_type type,
                            const char *name, int exclude)
 {
        struct packed_git *found_pack = NULL;
        off_t found_offset = 0;
        uint32_t index_pos;
 
-       if (have_duplicate_entry(sha1, exclude, &index_pos))
+       if (have_duplicate_entry(oid, exclude, &index_pos))
                return 0;
 
-       if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset)) {
+       if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
                /* The pack is missing an object, so it will not have closure */
                if (write_bitmap_index) {
                        warning(_(no_closure_warning));
@@ -1089,7 +1089,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
                return 0;
        }
 
-       create_object_entry(sha1, type, pack_name_hash(name),
+       create_object_entry(oid, type, pack_name_hash(name),
                            exclude, name && no_try_delta(name),
                            index_pos, found_pack, found_offset);
 
@@ -1097,27 +1097,27 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
        return 1;
 }
 
-static int add_object_entry_from_bitmap(const unsigned char *sha1,
+static int add_object_entry_from_bitmap(const struct object_id *oid,
                                        enum object_type type,
                                        int flags, uint32_t name_hash,
                                        struct packed_git *pack, off_t offset)
 {
        uint32_t index_pos;
 
-       if (have_duplicate_entry(sha1, 0, &index_pos))
+       if (have_duplicate_entry(oid, 0, &index_pos))
                return 0;
 
-       if (!want_object_in_pack(sha1, 0, &pack, &offset))
+       if (!want_object_in_pack(oid, 0, &pack, &offset))
                return 0;
 
-       create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset);
+       create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
 
        display_progress(progress_state, nr_result);
        return 1;
 }
 
 struct pbase_tree_cache {
-       unsigned char sha1[20];
+       struct object_id oid;
        int ref;
        int temporary;
        void *tree_data;
@@ -1125,9 +1125,9 @@ struct pbase_tree_cache {
 };
 
 static struct pbase_tree_cache *(pbase_tree_cache[256]);
-static int pbase_tree_cache_ix(const unsigned char *sha1)
+static int pbase_tree_cache_ix(const struct object_id *oid)
 {
-       return sha1[0] % ARRAY_SIZE(pbase_tree_cache);
+       return oid->hash[0] % ARRAY_SIZE(pbase_tree_cache);
 }
 static int pbase_tree_cache_ix_incr(int ix)
 {
@@ -1144,14 +1144,14 @@ static struct pbase_tree {
        struct pbase_tree_cache pcache;
 } *pbase_tree;
 
-static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
+static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
 {
        struct pbase_tree_cache *ent, *nent;
        void *data;
        unsigned long size;
        enum object_type type;
        int neigh;
-       int my_ix = pbase_tree_cache_ix(sha1);
+       int my_ix = pbase_tree_cache_ix(oid);
        int available_ix = -1;
 
        /* pbase-tree-cache acts as a limited hashtable.
@@ -1160,7 +1160,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
         */
        for (neigh = 0; neigh < 8; neigh++) {
                ent = pbase_tree_cache[my_ix];
-               if (ent && !hashcmp(ent->sha1, sha1)) {
+               if (ent && !oidcmp(&ent->oid, oid)) {
                        ent->ref++;
                        return ent;
                }
@@ -1176,7 +1176,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
        /* Did not find one.  Either we got a bogus request or
         * we need to read and perhaps cache.
         */
-       data = read_sha1_file(sha1, &type, &size);
+       data = read_sha1_file(oid->hash, &type, &size);
        if (!data)
                return NULL;
        if (type != OBJ_TREE) {
@@ -1202,7 +1202,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
                free(ent->tree_data);
                nent = ent;
        }
-       hashcpy(nent->sha1, sha1);
+       oidcpy(&nent->oid, oid);
        nent->tree_data = data;
        nent->tree_size = size;
        nent->ref = 1;
@@ -1247,7 +1247,7 @@ static void add_pbase_object(struct tree_desc *tree,
                if (cmp < 0)
                        return;
                if (name[cmplen] != '/') {
-                       add_object_entry(entry.oid->hash,
+                       add_object_entry(entry.oid,
                                         object_type(entry.mode),
                                         fullname, 1);
                        return;
@@ -1258,7 +1258,7 @@ static void add_pbase_object(struct tree_desc *tree,
                        const char *down = name+cmplen+1;
                        int downlen = name_cmp_len(down);
 
-                       tree = pbase_tree_get(entry.oid->hash);
+                       tree = pbase_tree_get(entry.oid);
                        if (!tree)
                                return;
                        init_tree_desc(&sub, tree->tree_data, tree->tree_size);
@@ -1317,7 +1317,7 @@ static void add_preferred_base_object(const char *name)
        cmplen = name_cmp_len(name);
        for (it = pbase_tree; it; it = it->next) {
                if (cmplen == 0) {
-                       add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1);
+                       add_object_entry(&it->pcache.oid, OBJ_TREE, NULL, 1);
                }
                else {
                        struct tree_desc tree;
@@ -1327,22 +1327,22 @@ static void add_preferred_base_object(const char *name)
        }
 }
 
-static void add_preferred_base(unsigned char *sha1)
+static void add_preferred_base(struct object_id *oid)
 {
        struct pbase_tree *it;
        void *data;
        unsigned long size;
-       unsigned char tree_sha1[20];
+       struct object_id tree_oid;
 
        if (window <= num_preferred_base++)
                return;
 
-       data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
+       data = read_object_with_reference(oid->hash, tree_type, &size, tree_oid.hash);
        if (!data)
                return;
 
        for (it = pbase_tree; it; it = it->next) {
-               if (!hashcmp(it->pcache.sha1, tree_sha1)) {
+               if (!oidcmp(&it->pcache.oid, &tree_oid)) {
                        free(data);
                        return;
                }
@@ -1352,7 +1352,7 @@ static void add_preferred_base(unsigned char *sha1)
        it->next = pbase_tree;
        pbase_tree = it;
 
-       hashcpy(it->pcache.sha1, tree_sha1);
+       oidcpy(&it->pcache.oid, &tree_oid);
        it->pcache.tree_data = data;
        it->pcache.tree_size = size;
 }
@@ -2357,7 +2357,7 @@ static void add_tag_chain(const struct object_id *oid)
                        die("unable to pack objects reachable from tag %s",
                            oid_to_hex(oid));
 
-               add_object_entry(tag->object.oid.hash, OBJ_TAG, NULL, 0);
+               add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
 
                if (tag->tagged->type != OBJ_TAG)
                        return;
@@ -2371,7 +2371,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
        struct object_id peeled;
 
        if (starts_with(path, "refs/tags/") && /* is a tag? */
-           !peel_ref(path, peeled.hash)    && /* peelable? */
+           !peel_ref(path, &peeled)    && /* peelable? */
            packlist_find(&to_pack, peeled.hash, NULL))      /* object packed? */
                add_tag_chain(oid);
        return 0;
@@ -2505,8 +2505,9 @@ static int git_pack_config(const char *k, const char *v, void *cb)
 
 static void read_object_list_from_stdin(void)
 {
-       char line[40 + 1 + PATH_MAX + 2];
-       unsigned char sha1[20];
+       char line[GIT_MAX_HEXSZ + 1 + PATH_MAX + 2];
+       struct object_id oid;
+       const char *p;
 
        for (;;) {
                if (!fgets(line, sizeof(line), stdin)) {
@@ -2520,17 +2521,17 @@ static void read_object_list_from_stdin(void)
                        continue;
                }
                if (line[0] == '-') {
-                       if (get_sha1_hex(line+1, sha1))
-                               die("expected edge sha1, got garbage:\n %s",
+                       if (get_oid_hex(line+1, &oid))
+                               die("expected edge object ID, got garbage:\n %s",
                                    line);
-                       add_preferred_base(sha1);
+                       add_preferred_base(&oid);
                        continue;
                }
-               if (get_sha1_hex(line, sha1))
-                       die("expected sha1, got garbage:\n %s", line);
+               if (parse_oid_hex(line, &oid, &p))
+                       die("expected object ID, got garbage:\n %s", line);
 
-               add_preferred_base_object(line+41);
-               add_object_entry(sha1, 0, line+41, 0);
+               add_preferred_base_object(p + 1);
+               add_object_entry(&oid, 0, p + 1, 0);
        }
 }
 
@@ -2538,7 +2539,7 @@ static void read_object_list_from_stdin(void)
 
 static void show_commit(struct commit *commit, void *data)
 {
-       add_object_entry(commit->object.oid.hash, OBJ_COMMIT, NULL, 0);
+       add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
        commit->object.flags |= OBJECT_ADDED;
 
        if (write_bitmap_index)
@@ -2548,13 +2549,13 @@ static void show_commit(struct commit *commit, void *data)
 static void show_object(struct object *obj, const char *name, void *data)
 {
        add_preferred_base_object(name);
-       add_object_entry(obj->oid.hash, obj->type, name, 0);
+       add_object_entry(&obj->oid, obj->type, name, 0);
        obj->flags |= OBJECT_ADDED;
 }
 
 static void show_edge(struct commit *commit)
 {
-       add_preferred_base(commit->object.oid.hash);
+       add_preferred_base(&commit->object.oid);
 }
 
 struct in_pack_object {
@@ -2601,7 +2602,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
        memset(&in_pack, 0, sizeof(in_pack));
 
        for (p = packed_git; p; p = p->next) {
-               const unsigned char *sha1;
+               struct object_id oid;
                struct object *o;
 
                if (!p->pack_local || p->pack_keep)
@@ -2614,8 +2615,8 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
                           in_pack.alloc);
 
                for (i = 0; i < p->num_objects; i++) {
-                       sha1 = nth_packed_object_sha1(p, i);
-                       o = lookup_unknown_object(sha1);
+                       nth_packed_object_oid(&oid, p, i);
+                       o = lookup_unknown_object(oid.hash);
                        if (!(o->flags & OBJECT_ADDED))
                                mark_in_pack_object(o, p, &in_pack);
                        o->flags |= OBJECT_ADDED;
@@ -2626,7 +2627,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
                QSORT(in_pack.array, in_pack.nr, ofscmp);
                for (i = 0; i < in_pack.nr; i++) {
                        struct object *o = in_pack.array[i].object;
-                       add_object_entry(o->oid.hash, o->type, "", 0);
+                       add_object_entry(&o->oid, o->type, "", 0);
                }
        }
        free(in_pack.array);
@@ -2642,7 +2643,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
                return 0;
        }
 
-       add_object_entry(oid->hash, type, "", 0);
+       add_object_entry(oid, type, "", 0);
        return 0;
 }
 
@@ -2658,7 +2659,7 @@ static void add_unreachable_loose_objects(void)
                                      NULL, NULL, NULL);
 }
 
-static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
+static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
 {
        static struct packed_git *last_found = (void *)1;
        struct packed_git *p;
@@ -2667,7 +2668,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
 
        while (p) {
                if ((!p->pack_local || p->pack_keep) &&
-                       find_pack_entry_one(sha1, p)) {
+                       find_pack_entry_one(oid->hash, p)) {
                        last_found = p;
                        return 1;
                }
@@ -2718,7 +2719,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                for (i = 0; i < p->num_objects; i++) {
                        nth_packed_object_oid(&oid, p, i);
                        if (!packlist_find(&to_pack, oid.hash, NULL) &&
-                           !has_sha1_pack_kept_or_nonlocal(oid.hash) &&
+                           !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
                                if (force_object_loose(oid.hash, p->mtime))
                                        die("unable to force loose object");
index 6f772e8..f7e2c4f 100644 (file)
@@ -86,6 +86,7 @@ static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static enum rebase_type opt_rebase = -1;
 static char *opt_diffstat;
 static char *opt_log;
+static char *opt_signoff;
 static char *opt_squash;
 static char *opt_commit;
 static char *opt_edit;
@@ -142,6 +143,9 @@ static struct option pull_options[] = {
        OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
                N_("add (at most <n>) entries from shortlog to merge commit message"),
                PARSE_OPT_OPTARG),
+       OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL,
+               N_("add Signed-off-by:"),
+               PARSE_OPT_OPTARG),
        OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
                N_("create a single commit instead of doing a merge"),
                PARSE_OPT_NOARG),
@@ -544,7 +548,7 @@ static int pull_into_void(const struct object_id *merge_head,
        if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
                return 1;
 
-       if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
+       if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
                return 1;
 
        return 0;
@@ -594,6 +598,8 @@ static int run_merge(void)
                argv_array_push(&args, opt_diffstat);
        if (opt_log)
                argv_array_push(&args, opt_log);
+       if (opt_signoff)
+               argv_array_push(&args, opt_signoff);
        if (opt_squash)
                argv_array_push(&args, opt_squash);
        if (opt_commit)
@@ -745,12 +751,15 @@ static int get_octopus_merge_base(struct object_id *merge_base,
        if (!is_null_oid(fork_point))
                commit_list_insert(lookup_commit_reference(fork_point), &revs);
 
-       result = reduce_heads(get_octopus_merge_bases(revs));
+       result = get_octopus_merge_bases(revs);
        free_commit_list(revs);
+       reduce_heads_replace(&result);
+
        if (!result)
                return 1;
 
        oidcpy(merge_base, &result->item->object.oid);
+       free_commit_list(result);
        return 0;
 }
 
index 2ac8104..1c28427 100644 (file)
@@ -32,6 +32,8 @@ static const char **refspec;
 static int refspec_nr;
 static int refspec_alloc;
 
+static struct string_list push_options_config = STRING_LIST_INIT_DUP;
+
 static void add_refspec(const char *ref)
 {
        refspec_nr++;
@@ -503,6 +505,15 @@ static int git_push_config(const char *k, const char *v, void *cb)
                int val = git_config_bool(k, v) ?
                        RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
                recurse_submodules = val;
+       } else if (!strcmp(k, "push.pushoption")) {
+               if (!v)
+                       return config_error_nonbool(k);
+               else
+                       if (!*v)
+                               string_list_clear(&push_options_config, 0);
+                       else
+                               string_list_append(&push_options_config, v);
+               return 0;
        }
 
        return git_default_config(k, v, NULL);
@@ -515,7 +526,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        int push_cert = -1;
        int rc;
        const char *repo = NULL;        /* default repository */
-       struct string_list push_options = STRING_LIST_INIT_DUP;
+       struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
+       struct string_list *push_options;
        const struct string_list_item *item;
 
        struct option options[] = {
@@ -551,7 +563,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                  0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
                  PARSE_OPT_OPTARG, option_parse_push_signed },
                OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
-               OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
+               OPT_STRING_LIST('o', "push-option", &push_options_cmdline, 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"),
@@ -562,6 +574,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        packet_trace_identity("push");
        git_config(git_push_config, &flags);
        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
+       push_options = (push_options_cmdline.nr
+               ? &push_options_cmdline
+               : &push_options_config);
        set_push_cert_flags(&flags, push_cert);
 
        if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
@@ -584,12 +599,13 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                set_refspecs(argv + 1, argc - 1, repo);
        }
 
-       for_each_string_list_item(item, &push_options)
+       for_each_string_list_item(item, push_options)
                if (strchr(item->string, '\n'))
                        die(_("push options must not have new line characters"));
 
-       rc = do_push(repo, flags, &push_options);
-       string_list_clear(&push_options, 0);
+       rc = do_push(repo, flags, push_options);
+       string_list_clear(&push_options_cmdline, 0);
+       string_list_clear(&push_options_config, 0);
        if (rc == -1)
                usage_with_options(push_usage, options);
        else
index cc48767..4d37a16 100644 (file)
@@ -870,7 +870,7 @@ static void refuse_unconfigured_deny_delete_current(void)
        rp_error("%s", _(refuse_unconfigured_deny_delete_current_msg));
 }
 
-static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]);
+static int command_singleton_iterator(void *cb_data, struct object_id *oid);
 static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
 {
        static struct lock_file shallow_lock;
@@ -1139,7 +1139,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
                if (ref_transaction_delete(transaction,
                                           namespaced_name,
-                                          old_oid ? old_oid->hash : NULL,
+                                          old_oid,
                                           0, "push", &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
@@ -1156,7 +1156,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 
                if (ref_transaction_update(transaction,
                                           namespaced_name,
-                                          new_oid->hash, old_oid->hash,
+                                          new_oid, old_oid,
                                           0, "push",
                                           &err)) {
                        rp_error("%s", err.buf);
@@ -1270,7 +1270,7 @@ static void check_aliased_updates(struct command *commands)
        string_list_clear(&ref_list, 0);
 }
 
-static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
+static int command_singleton_iterator(void *cb_data, struct object_id *oid)
 {
        struct command **cmd_list = cb_data;
        struct command *cmd = *cmd_list;
@@ -1278,7 +1278,7 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
        if (!cmd || is_null_oid(&cmd->new_oid))
                return -1; /* end of list */
        *cmd_list = NULL; /* this returns only one */
-       hashcpy(sha1, cmd->new_oid.hash);
+       oidcpy(oid, &cmd->new_oid);
        return 0;
 }
 
@@ -1309,7 +1309,7 @@ struct iterate_data {
        struct shallow_info *si;
 };
 
-static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
+static int iterate_receive_command_list(void *cb_data, struct object_id *oid)
 {
        struct iterate_data *data = cb_data;
        struct command **cmd_list = &data->cmds;
@@ -1320,7 +1320,7 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
                        /* to be checked in update_shallow_ref() */
                        continue;
                if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) {
-                       hashcpy(sha1, cmd->new_oid.hash);
+                       oidcpy(oid, &cmd->new_oid);
                        *cmd_list = cmd->next;
                        return 0;
                }
index 2067cca..ab31a3b 100644 (file)
@@ -42,7 +42,7 @@ struct expire_reflog_policy_cb {
 };
 
 struct collected_reflog {
-       unsigned char sha1[20];
+       struct object_id oid;
        char reflog[FLEX_ARRAY];
 };
 
@@ -385,7 +385,7 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
        struct collect_reflog_cb *cb = cb_data;
 
        FLEX_ALLOC_STR(e, reflog, ref);
-       hashcpy(e->sha1, oid->hash);
+       oidcpy(&e->oid, oid);
        ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
        cb->e[cb->nr++] = e;
        return 0;
@@ -589,7 +589,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                for (i = 0; i < collected.nr; i++) {
                        struct collected_reflog *e = collected.e[i];
                        set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
-                       status |= reflog_expire(e->reflog, e->sha1, flags,
+                       status |= reflog_expire(e->reflog, &e->oid, flags,
                                                reflog_expiry_prepare,
                                                should_expire_reflog_ent,
                                                reflog_expiry_cleanup,
@@ -601,13 +601,13 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 
        for (; i < argc; i++) {
                char *ref;
-               unsigned char sha1[20];
-               if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) {
+               struct object_id oid;
+               if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) {
                        status |= error("%s points nowhere!", argv[i]);
                        continue;
                }
                set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
-               status |= reflog_expire(ref, sha1, flags,
+               status |= reflog_expire(ref, &oid, flags,
                                        reflog_expiry_prepare,
                                        should_expire_reflog_ent,
                                        reflog_expiry_cleanup,
@@ -659,7 +659,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
 
        for ( ; i < argc; i++) {
                const char *spec = strstr(argv[i], "@{");
-               unsigned char sha1[20];
+               struct object_id oid;
                char *ep, *ref;
                int recno;
 
@@ -668,7 +668,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
+               if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) {
                        status |= error("no reflog for '%s'", argv[i]);
                        continue;
                }
@@ -683,7 +683,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
                        cb.cmd.expire_total = 0;
                }
 
-               status |= reflog_expire(ref, sha1, flags,
+               status |= reflog_expire(ref, &oid, flags,
                                        reflog_expiry_prepare,
                                        should_expire_reflog_ent,
                                        reflog_expiry_cleanup,
index bc89623..d95bf90 100644 (file)
@@ -690,10 +690,10 @@ static int mv(int argc, const char **argv)
                int flag = 0;
                struct object_id oid;
 
-               read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag);
+               read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
                if (!(flag & REF_ISSYMREF))
                        continue;
-               if (delete_ref(NULL, item->string, NULL, REF_NODEREF))
+               if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
                        die(_("deleting '%s' failed"), item->string);
        }
        for (i = 0; i < remote_branches.nr; i++) {
@@ -788,7 +788,7 @@ static int rm(int argc, const char **argv)
        strbuf_release(&buf);
 
        if (!result)
-               result = delete_refs("remote: remove", &branches, REF_NODEREF);
+               result = delete_refs("remote: remove", &branches, REF_NO_DEREF);
        string_list_clear(&branches, 0);
 
        if (skipped.nr) {
@@ -1255,7 +1255,7 @@ static int set_head(int argc, const char **argv)
                        head_name = xstrdup(states.heads.items[0].string);
                free_remote_ref_states(&states);
        } else if (opt_d && !opt_a && argc == 1) {
-               if (delete_ref(NULL, buf.buf, NULL, REF_NODEREF))
+               if (delete_ref(NULL, buf.buf, NULL, REF_NO_DEREF))
                        result |= error(_("Could not delete %s"), buf.buf);
        } else
                usage_with_options(builtin_remote_sethead_usage, options);
index 3e71a77..10078ae 100644 (file)
@@ -113,7 +113,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
                strbuf_addstr(&ref, oid_to_hex(&oid));
                full_hex = ref.buf + base_len;
 
-               if (read_ref(ref.buf, oid.hash)) {
+               if (read_ref(ref.buf, &oid)) {
                        error("replace ref '%s' not found.", full_hex);
                        had_error = 1;
                        continue;
@@ -128,7 +128,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
 static int delete_replace_ref(const char *name, const char *ref,
                              const struct object_id *oid)
 {
-       if (delete_ref(NULL, ref, oid->hash, 0))
+       if (delete_ref(NULL, ref, oid, 0))
                return 1;
        printf("Deleted replace ref '%s'\n", name);
        return 0;
@@ -144,7 +144,7 @@ static void check_ref_valid(struct object_id *object,
        if (check_refname_format(ref->buf, 0))
                die("'%s' is not a valid ref name.", ref->buf);
 
-       if (read_ref(ref->buf, prev->hash))
+       if (read_ref(ref->buf, prev))
                oidclr(prev);
        else if (!force)
                die("replace ref '%s' already exists", ref->buf);
@@ -175,7 +175,7 @@ static int replace_object_oid(const char *object_ref,
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash,
+           ref_transaction_update(transaction, ref.buf, repl, &prev,
                                   0, NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
index 9cd89b2..906e541 100644 (file)
@@ -166,7 +166,7 @@ static int read_from_tree(const struct pathspec *pathspec,
        opt.output_format = DIFF_FORMAT_CALLBACK;
        opt.format_callback = update_index_from_diff;
        opt.format_callback_data = &intent_to_add;
-       opt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+       opt.flags.override_submodule_config = 1;
 
        if (do_diff_cache(tree_oid, &opt))
                return 1;
@@ -266,12 +266,12 @@ static int reset_refs(const char *rev, const struct object_id *oid)
        if (!get_oid("HEAD", &oid_orig)) {
                orig = &oid_orig;
                set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
-               update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
+               update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
                           UPDATE_REFS_MSG_ON_ERR);
        } else if (old_orig)
-               delete_ref(NULL, "ORIG_HEAD", old_orig->hash, 0);
+               delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
        set_reflog_message(&msg, "updating HEAD", rev);
-       update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0,
+       update_ref_status = update_ref(msg.buf, "HEAD", oid, orig, 0,
                                       UPDATE_REFS_MSG_ON_ERR);
        strbuf_release(&msg);
        return update_ref_status;
index c1c74d4..4032eb3 100644 (file)
@@ -258,14 +258,14 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
 }
 
 static int show_object_fast(
-       const unsigned char *sha1,
+       const struct object_id *oid,
        enum object_type type,
        int exclude,
        uint32_t name_hash,
        struct packed_git *found_pack,
        off_t found_offset)
 {
-       fprintf(stdout, "%s\n", sha1_to_hex(sha1));
+       fprintf(stdout, "%s\n", oid_to_hex(oid));
        return 1;
 }
 
@@ -294,7 +294,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        if (revs.bisect)
                bisect_list = 1;
 
-       if (DIFF_OPT_TST(&revs.diffopt, QUICK))
+       if (revs.diffopt.flags.quick)
                info.flags |= REV_LIST_QUIET;
        for (i = 1 ; i < argc; i++) {
                const char *arg = argv[i];
@@ -397,8 +397,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        if (bisect_list) {
                int reaches = reaches, all = all;
 
-               revs.commits = find_bisection(revs.commits, &reaches, &all,
-                                             bisect_find_all);
+               find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
 
                if (bisect_show_vars)
                        return show_bisect_vars(&info, reaches, all);
index a8d7e6f..74aa644 100644 (file)
@@ -133,7 +133,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
                        struct object_id discard;
                        char *full;
 
-                       switch (dwim_ref(name, strlen(name), discard.hash, &full)) {
+                       switch (dwim_ref(name, strlen(name), &discard, &full)) {
                        case 0:
                                /*
                                 * Not found -- not a ref.  We could
index 6fa1f62..2e24b5c 100644 (file)
@@ -705,8 +705,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        static const char *fake_av[2];
 
                        fake_av[0] = resolve_refdup("HEAD",
-                                                   RESOLVE_REF_READING,
-                                                   oid.hash, NULL);
+                                                   RESOLVE_REF_READING, &oid,
+                                                   NULL);
                        fake_av[1] = NULL;
                        av = fake_av;
                        ac = 1;
@@ -720,7 +720,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        die(Q_("only %d entry can be shown at one time.",
                               "only %d entries can be shown at one time.",
                               MAX_REVS), MAX_REVS);
-               if (!dwim_ref(*av, strlen(*av), oid.hash, &ref))
+               if (!dwim_ref(*av, strlen(*av), &oid, &ref))
                        die(_("no such ref %s"), *av);
 
                /* Has the base been specified? */
@@ -731,7 +731,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                                /* Ah, that is a date spec... */
                                timestamp_t at;
                                at = approxidate(reflog_base);
-                               read_ref_at(ref, flags, at, -1, oid.hash, NULL,
+                               read_ref_at(ref, flags, at, -1, &oid, NULL,
                                            NULL, NULL, &base);
                        }
                }
@@ -743,7 +743,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        timestamp_t timestamp;
                        int tz;
 
-                       if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
+                       if (read_ref_at(ref, flags, 0, base + i, &oid, &logmsg,
                                        &timestamp, &tz, NULL)) {
                                reflog = i;
                                break;
@@ -775,7 +775,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
        }
 
        head = resolve_refdup("HEAD", RESOLVE_REF_READING,
-                             head_oid.hash, NULL);
+                             &head_oid, NULL);
 
        if (with_current_branch && head) {
                int has_head = 0;
index 013d241..41e5e71 100644 (file)
@@ -38,7 +38,7 @@ static void show_one(const char *refname, const struct object_id *oid)
        if (!deref_tags)
                return;
 
-       if (!peel_ref(refname, peeled.hash)) {
+       if (!peel_ref(refname, &peeled)) {
                hex = find_unique_abbrev(peeled.hash, abbrev);
                printf("%s %s^{}\n", hex, refname);
        }
@@ -197,7 +197,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
                        struct object_id oid;
 
                        if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) &&
-                           !read_ref(*pattern, oid.hash)) {
+                           !read_ref(*pattern, &oid)) {
                                show_one(*pattern, &oid);
                        }
                        else if (!quiet)
index 06ed02f..2086f0e 100644 (file)
 #include "remote.h"
 #include "refs.h"
 #include "connect.h"
+#include "revision.h"
+#include "diffcore.h"
+#include "diff.h"
+
+#define OPT_QUIET (1 << 0)
+#define OPT_CACHED (1 << 1)
+#define OPT_RECURSIVE (1 << 2)
+
+typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
+                                 void *cb_data);
 
 static char *get_default_remote(void)
 {
@@ -219,6 +229,64 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
        return 0;
 }
 
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+       const char *super_prefix = get_super_prefix();
+
+       if (prefix && super_prefix) {
+               BUG("cannot have prefix '%s' and superprefix '%s'",
+                   prefix, super_prefix);
+       } else if (prefix) {
+               struct strbuf sb = STRBUF_INIT;
+               char *displaypath = xstrdup(relative_path(path, prefix, &sb));
+               strbuf_release(&sb);
+               return displaypath;
+       } else if (super_prefix) {
+               return xstrfmt("%s%s", super_prefix, path);
+       } else {
+               return xstrdup(path);
+       }
+}
+
+static char *compute_rev_name(const char *sub_path, const char* object_id)
+{
+       struct strbuf sb = STRBUF_INIT;
+       const char ***d;
+
+       static const char *describe_bare[] = { NULL };
+
+       static const char *describe_tags[] = { "--tags", NULL };
+
+       static const char *describe_contains[] = { "--contains", NULL };
+
+       static const char *describe_all_always[] = { "--all", "--always", NULL };
+
+       static const char **describe_argv[] = { describe_bare, describe_tags,
+                                               describe_contains,
+                                               describe_all_always, NULL };
+
+       for (d = describe_argv; *d; d++) {
+               struct child_process cp = CHILD_PROCESS_INIT;
+               prepare_submodule_repo_env(&cp.env_array);
+               cp.dir = sub_path;
+               cp.git_cmd = 1;
+               cp.no_stderr = 1;
+
+               argv_array_push(&cp.args, "describe");
+               argv_array_pushv(&cp.args, *d);
+               argv_array_push(&cp.args, object_id);
+
+               if (!capture_command(&cp, &sb, 0)) {
+                       strbuf_strip_suffix(&sb, "\n");
+                       return strbuf_detach(&sb, NULL);
+               }
+       }
+
+       strbuf_release(&sb);
+       return NULL;
+}
+
 struct module_list {
        const struct cache_entry **entries;
        int alloc, nr;
@@ -328,21 +396,29 @@ static int module_list(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
-static void init_submodule(const char *path, const char *prefix, int quiet)
+static void for_each_listed_submodule(const struct module_list *list,
+                                     each_submodule_fn fn, void *cb_data)
+{
+       int i;
+       for (i = 0; i < list->nr; i++)
+               fn(list->entries[i], cb_data);
+}
+
+struct init_cb {
+       const char *prefix;
+       unsigned int flags;
+};
+
+#define INIT_CB_INIT { NULL, 0 }
+
+static void init_submodule(const char *path, const char *prefix,
+                          unsigned int flags)
 {
        const struct submodule *sub;
        struct strbuf sb = STRBUF_INIT;
        char *upd = NULL, *url = NULL, *displaypath;
 
-       if (prefix && get_super_prefix())
-               die("BUG: cannot have prefix and superprefix");
-       else if (prefix)
-               displaypath = xstrdup(relative_path(path, prefix, &sb));
-       else if (get_super_prefix()) {
-               strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
-               displaypath = strbuf_detach(&sb, NULL);
-       } else
-               displaypath = xstrdup(path);
+       displaypath = get_submodule_displaypath(path, prefix);
 
        sub = submodule_from_path(&null_oid, path);
 
@@ -357,9 +433,9 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
         * Set active flag for the submodule being initialized
         */
        if (!is_submodule_active(the_repository, path)) {
-               strbuf_reset(&sb);
                strbuf_addf(&sb, "submodule.%s.active", sub->name);
                git_config_set_gently(sb.buf, "true");
+               strbuf_reset(&sb);
        }
 
        /*
@@ -367,7 +443,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
         * To look up the url in .git/config, we must not fall back to
         * .gitmodules, so look it up directly.
         */
-       strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
        if (git_config_get_string(sb.buf, &url)) {
                if (!sub->url)
@@ -399,14 +474,14 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
                if (git_config_set_gently(sb.buf, url))
                        die(_("Failed to register url for submodule path '%s'"),
                            displaypath);
-               if (!quiet)
+               if (!(flags & OPT_QUIET))
                        fprintf(stderr,
                                _("Submodule '%s' (%s) registered for path '%s'\n"),
                                sub->name, url, displaypath);
        }
+       strbuf_reset(&sb);
 
        /* Copy "update" setting when it is not set yet */
-       strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.update", sub->name);
        if (git_config_get_string(sb.buf, &upd) &&
            sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
@@ -426,12 +501,18 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
        free(upd);
 }
 
+static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
+{
+       struct init_cb *info = cb_data;
+       init_submodule(list_item->name, info->prefix, info->flags);
+}
+
 static int module_init(int argc, const char **argv, const char *prefix)
 {
+       struct init_cb info = INIT_CB_INIT;
        struct pathspec pathspec;
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
-       int i;
 
        struct option module_init_options[] = {
                OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
@@ -456,8 +537,165 @@ static int module_init(int argc, const char **argv, const char *prefix)
        if (!argc && git_config_get_value_multi("submodule.active"))
                module_list_active(&list);
 
-       for (i = 0; i < list.nr; i++)
-               init_submodule(list.entries[i]->name, prefix, quiet);
+       info.prefix = prefix;
+       if (quiet)
+               info.flags |= OPT_QUIET;
+
+       for_each_listed_submodule(&list, init_submodule_cb, &info);
+
+       return 0;
+}
+
+struct status_cb {
+       const char *prefix;
+       unsigned int flags;
+};
+
+#define STATUS_CB_INIT { NULL, 0 }
+
+static void print_status(unsigned int flags, char state, const char *path,
+                        const struct object_id *oid, const char *displaypath)
+{
+       if (flags & OPT_QUIET)
+               return;
+
+       printf("%c%s %s", state, oid_to_hex(oid), displaypath);
+
+       if (state == ' ' || state == '+')
+               printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
+
+       printf("\n");
+}
+
+static int handle_submodule_head_ref(const char *refname,
+                                    const struct object_id *oid, int flags,
+                                    void *cb_data)
+{
+       struct object_id *output = cb_data;
+       if (oid)
+               oidcpy(output, oid);
+
+       return 0;
+}
+
+static void status_submodule(const char *path, const struct object_id *ce_oid,
+                            unsigned int ce_flags, const char *prefix,
+                            unsigned int flags)
+{
+       char *displaypath;
+       struct argv_array diff_files_args = ARGV_ARRAY_INIT;
+       struct rev_info rev;
+       int diff_files_result;
+
+       if (!submodule_from_path(&null_oid, path))
+               die(_("no submodule mapping found in .gitmodules for path '%s'"),
+                     path);
+
+       displaypath = get_submodule_displaypath(path, prefix);
+
+       if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
+               print_status(flags, 'U', path, &null_oid, displaypath);
+               goto cleanup;
+       }
+
+       if (!is_submodule_active(the_repository, path)) {
+               print_status(flags, '-', path, ce_oid, displaypath);
+               goto cleanup;
+       }
+
+       argv_array_pushl(&diff_files_args, "diff-files",
+                        "--ignore-submodules=dirty", "--quiet", "--",
+                        path, NULL);
+
+       git_config(git_diff_basic_config, NULL);
+       init_revisions(&rev, prefix);
+       rev.abbrev = 0;
+       diff_files_args.argc = setup_revisions(diff_files_args.argc,
+                                              diff_files_args.argv,
+                                              &rev, NULL);
+       diff_files_result = run_diff_files(&rev, 0);
+
+       if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+               print_status(flags, ' ', path, ce_oid,
+                            displaypath);
+       } else if (!(flags & OPT_CACHED)) {
+               struct object_id oid;
+
+               if (refs_head_ref(get_submodule_ref_store(path),
+                                 handle_submodule_head_ref, &oid))
+                       die(_("could not resolve HEAD ref inside the"
+                             "submodule '%s'"), path);
+
+               print_status(flags, '+', path, &oid, displaypath);
+       } else {
+               print_status(flags, '+', path, ce_oid, displaypath);
+       }
+
+       if (flags & OPT_RECURSIVE) {
+               struct child_process cpr = CHILD_PROCESS_INIT;
+
+               cpr.git_cmd = 1;
+               cpr.dir = path;
+               prepare_submodule_repo_env(&cpr.env_array);
+
+               argv_array_push(&cpr.args, "--super-prefix");
+               argv_array_pushf(&cpr.args, "%s/", displaypath);
+               argv_array_pushl(&cpr.args, "submodule--helper", "status",
+                                "--recursive", NULL);
+
+               if (flags & OPT_CACHED)
+                       argv_array_push(&cpr.args, "--cached");
+
+               if (flags & OPT_QUIET)
+                       argv_array_push(&cpr.args, "--quiet");
+
+               if (run_command(&cpr))
+                       die(_("failed to recurse into submodule '%s'"), path);
+       }
+
+cleanup:
+       argv_array_clear(&diff_files_args);
+       free(displaypath);
+}
+
+static void status_submodule_cb(const struct cache_entry *list_item,
+                               void *cb_data)
+{
+       struct status_cb *info = cb_data;
+       status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
+                        info->prefix, info->flags);
+}
+
+static int module_status(int argc, const char **argv, const char *prefix)
+{
+       struct status_cb info = STATUS_CB_INIT;
+       struct pathspec pathspec;
+       struct module_list list = MODULE_LIST_INIT;
+       int quiet = 0;
+
+       struct option module_status_options[] = {
+               OPT__QUIET(&quiet, N_("Suppress submodule status output")),
+               OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
+               OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
+               OPT_END()
+       };
+
+       const char *const git_submodule_helper_usage[] = {
+               N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
+               NULL
+       };
+
+       argc = parse_options(argc, argv, prefix, module_status_options,
+                            git_submodule_helper_usage, 0);
+
+       if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+               return 1;
+
+       info.prefix = prefix;
+       if (quiet)
+               info.flags |= OPT_QUIET;
+
+       for_each_listed_submodule(&list, status_submodule_cb, &info);
 
        return 0;
 }
@@ -1144,7 +1382,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
        argv++;
        argc--;
        /* Get the submodule's head ref and determine if it is detached */
-       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
        if (!strcmp(head, "HEAD"))
@@ -1259,6 +1497,7 @@ static struct cmd_struct commands[] = {
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
+       {"status", module_status, SUPPORT_SUPER_PREFIX},
        {"remote-branch", resolve_remote_submodule_branch, 0},
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
index 17aabaa..80237f0 100644 (file)
@@ -58,7 +58,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
                        die("Cannot delete %s, not a symbolic ref", argv[0]);
                if (!strcmp(argv[0], "HEAD"))
                        die("deleting '%s' is not allowed", argv[0]);
-               return delete_ref(NULL, argv[0], NULL, REF_NODEREF);
+               return delete_ref(NULL, argv[0], NULL, REF_NO_DEREF);
        }
 
        switch (argc) {
index b38329b..a7e6a5b 100644 (file)
@@ -82,7 +82,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
        for (p = argv; *p; p++) {
                strbuf_reset(&ref);
                strbuf_addf(&ref, "refs/tags/%s", *p);
-               if (read_ref(ref.buf, oid.hash)) {
+               if (read_ref(ref.buf, &oid)) {
                        error(_("tag '%s' not found."), *p);
                        had_error = 1;
                        continue;
@@ -97,7 +97,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
 static int delete_tag(const char *name, const char *ref,
                      const struct object_id *oid, const void *cb_data)
 {
-       if (delete_ref(NULL, ref, oid->hash, 0))
+       if (delete_ref(NULL, ref, oid, 0))
                return 1;
        printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
        return 0;
@@ -518,7 +518,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (strbuf_check_tag_ref(&ref, tag))
                die(_("'%s' is not a valid tag name."), tag);
 
-       if (read_ref(ref.buf, prev.hash))
+       if (read_ref(ref.buf, &prev))
                oidclr(&prev);
        else if (!force)
                die(_("tag '%s' already exists"), tag);
@@ -544,7 +544,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
+           ref_transaction_update(transaction, ref.buf, &object, &prev,
                                   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
                                   reflog_msg.buf, &err) ||
            ref_transaction_commit(transaction, &err))
index bf7420b..fefbe60 100644 (file)
@@ -328,7 +328,7 @@ static int process_directory(const char *path, int len, struct stat *st)
                if (S_ISGITLINK(ce->ce_mode)) {
 
                        /* Do nothing to the index if there is no HEAD! */
-                       if (resolve_gitlink_ref(path, "HEAD", oid.hash) < 0)
+                       if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
                                return 0;
 
                        return add_one_path(ce, path, len, st);
@@ -354,7 +354,7 @@ static int process_directory(const char *path, int len, struct stat *st)
        }
 
        /* No match - should we add it as a gitlink? */
-       if (!resolve_gitlink_ref(path, "HEAD", oid.hash))
+       if (!resolve_gitlink_ref(path, "HEAD", &oid))
                return add_one_path(NULL, path, len, st);
 
        /* Error out. */
@@ -679,9 +679,9 @@ static int unresolve_one(const char *path)
 
 static void read_head_pointers(void)
 {
-       if (read_ref("HEAD", head_oid.hash))
+       if (read_ref("HEAD", &head_oid))
                die("No HEAD -- no initial commit yet?");
-       if (read_ref("MERGE_HEAD", merge_head_oid.hash)) {
+       if (read_ref("MERGE_HEAD", &merge_head_oid)) {
                fprintf(stderr, "Not in the middle of a merge.\n");
                exit(0);
        }
@@ -721,7 +721,7 @@ static int do_reupdate(int ac, const char **av,
                       PATHSPEC_PREFER_CWD,
                       prefix, av + 1);
 
-       if (read_ref("HEAD", head_oid.hash))
+       if (read_ref("HEAD", &head_oid))
                /* If there is no HEAD, that means it is an initial
                 * commit.  Update everything in the index.
                 */
index 6b90c5d..4b4714b 100644 (file)
@@ -200,7 +200,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
                die("update %s: extra input: %s", refname, next);
 
        if (ref_transaction_update(transaction, refname,
-                                  new_oid.hash, have_old ? old_oid.hash : NULL,
+                                  &new_oid, have_old ? &old_oid : NULL,
                                   update_flags | create_reflog_flag,
                                   msg, &err))
                die("%s", err.buf);
@@ -232,7 +232,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
        if (*next != line_termination)
                die("create %s: extra input: %s", refname, next);
 
-       if (ref_transaction_create(transaction, refname, new_oid.hash,
+       if (ref_transaction_create(transaction, refname, &new_oid,
                                   update_flags | create_reflog_flag,
                                   msg, &err))
                die("%s", err.buf);
@@ -269,7 +269,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
                die("delete %s: extra input: %s", refname, next);
 
        if (ref_transaction_delete(transaction, refname,
-                                  have_old ? old_oid.hash : NULL,
+                                  have_old ? &old_oid : NULL,
                                   update_flags, msg, &err))
                die("%s", err.buf);
 
@@ -298,7 +298,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
        if (*next != line_termination)
                die("verify %s: extra input: %s", refname, next);
 
-       if (ref_transaction_verify(transaction, refname, old_oid.hash,
+       if (ref_transaction_verify(transaction, refname, &old_oid,
                                   update_flags, &err))
                die("%s", err.buf);
 
@@ -312,7 +312,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
 static const char *parse_cmd_option(struct strbuf *input, const char *next)
 {
        if (!strncmp(next, "no-deref", 8) && next[8] == line_termination)
-               update_flags |= REF_NODEREF;
+               update_flags |= REF_NO_DEREF;
        else
                die("option unknown: %s", next);
        return next + 8;
@@ -427,17 +427,17 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        }
 
        if (no_deref)
-               flags = REF_NODEREF;
+               flags = REF_NO_DEREF;
        if (delete)
                /*
                 * For purposes of backwards compatibility, we treat
                 * NULL_SHA1 as "don't care" here:
                 */
                return delete_ref(msg, refname,
-                                 (oldval && !is_null_oid(&oldoid)) ? oldoid.hash : NULL,
+                                 (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
                                  flags);
        else
-               return update_ref(msg, refname, oid.hash, oldval ? oldoid.hash : NULL,
+               return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
                                  flags | create_reflog_flag,
                                  UPDATE_REFS_DIE_ON_ERR);
 }
index 7b9307a..ed043d5 100644 (file)
@@ -410,7 +410,7 @@ static void show_worktree_porcelain(struct worktree *wt)
        if (wt->is_bare)
                printf("bare\n");
        else {
-               printf("HEAD %s\n", sha1_to_hex(wt->head_sha1));
+               printf("HEAD %s\n", oid_to_hex(&wt->head_oid));
                if (wt->is_detached)
                        printf("detached\n");
                else if (wt->head_ref)
@@ -430,7 +430,7 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
                strbuf_addstr(&sb, "(bare)");
        else {
                strbuf_addf(&sb, "%-*s ", abbrev_len,
-                               find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
+                               find_unique_abbrev(wt->head_oid.hash, DEFAULT_ABBREV));
                if (wt->is_detached)
                        strbuf_addstr(&sb, "(detached HEAD)");
                else if (wt->head_ref) {
@@ -455,7 +455,7 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
 
                if (path_len > *maxlen)
                        *maxlen = path_len;
-               sha1_len = strlen(find_unique_abbrev(wt[i]->head_sha1, *abbrev));
+               sha1_len = strlen(find_unique_abbrev(wt[i]->head_oid.hash, *abbrev));
                if (sha1_len > *abbrev)
                        *abbrev = sha1_len;
        }
index c092d5d..9329096 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -338,9 +338,9 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
 
                if (e->item->flags & UNINTERESTING)
                        continue;
-               if (dwim_ref(e->name, strlen(e->name), oid.hash, &ref) != 1)
+               if (dwim_ref(e->name, strlen(e->name), &oid, &ref) != 1)
                        goto skip_write_ref;
-               if (read_ref_full(e->name, RESOLVE_REF_READING, oid.hash, &flag))
+               if (read_ref_full(e->name, RESOLVE_REF_READING, &oid, &flag))
                        flag = 0;
                display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
 
index d3f7401..e03e72c 100644 (file)
@@ -602,11 +602,11 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
 
 int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
 {
-       int entries, was_valid, newfd;
+       int entries, was_valid;
        struct lock_file lock_file = LOCK_INIT;
        int ret = 0;
 
-       newfd = hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
+       hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
 
        entries = read_index_from(index_state, index_path);
        if (entries < 0) {
@@ -625,10 +625,7 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
                        ret = WRITE_TREE_UNMERGED_INDEX;
                        goto out;
                }
-               if (0 <= newfd) {
-                       if (!write_locked_index(index_state, &lock_file, COMMIT_LOCK))
-                               newfd = -1;
-               }
+               write_locked_index(index_state, &lock_file, COMMIT_LOCK);
                /* Not being able to write is fine -- we are only interested
                 * in updating the cache-tree part, and if the next caller
                 * ends up using the old index with unupdated cache-tree part
@@ -650,8 +647,7 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
                hashcpy(sha1, index_state->cache_tree->oid.hash);
 
 out:
-       if (0 <= newfd)
-               rollback_lock_file(&lock_file);
+       rollback_lock_file(&lock_file);
        return ret;
 }
 
diff --git a/cache.h b/cache.h
index 6440e2b..89f5d24 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -602,9 +602,28 @@ extern int do_read_index(struct index_state *istate, const char *path,
 extern int read_index_from(struct index_state *, const char *path);
 extern int is_index_unborn(struct index_state *);
 extern int read_index_unmerged(struct index_state *);
+
+/* For use with `write_locked_index()`. */
 #define COMMIT_LOCK            (1 << 0)
-#define CLOSE_LOCK             (1 << 1)
+
+/*
+ * Write the index while holding an already-taken lock. Close the lock,
+ * and if `COMMIT_LOCK` is given, commit it.
+ *
+ * Unless a split index is in use, write the index into the lockfile.
+ *
+ * With a split index, write the shared index to a temporary file,
+ * adjust its permissions and rename it into place, then write the
+ * split index to the lockfile. If the temporary file for the shared
+ * index cannot be created, fall back to the behavior described in
+ * the previous paragraph.
+ *
+ * With `COMMIT_LOCK`, the lock is always committed or rolled back.
+ * Without it, the lock is closed, but neither committed nor rolled
+ * back.
+ */
 extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
+
 extern int discard_index(struct index_state *);
 extern void move_index_extensions(struct index_state *dst, struct index_state *src);
 extern int unmerged_index(const struct index_state *);
@@ -716,12 +735,17 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
 extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
 
+/*
+ * Opportunistically update the index but do not complain if we can't.
+ * The lockfile is always committed or rolled back.
+ */
 extern void update_index_if_able(struct index_state *, struct lock_file *);
 
 extern int hold_locked_index(struct lock_file *, int);
 extern void set_alternate_index_output(const char *);
 
 extern int verify_index_checksum;
+extern int verify_ce_order;
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
@@ -1317,6 +1341,13 @@ extern int set_disambiguate_hint_config(const char *var, const char *value);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern int get_oid_hex(const char *hex, struct object_id *sha1);
 
+/*
+ * Read `len` pairs of hexadecimal digits from `hex` and write the
+ * values to `binary` as `len` bytes. Return 0 on success, or -1 if
+ * the input does not consist of hex digits).
+ */
+extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
+
 /*
  * Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant,
  * and writes the NUL-terminated output to the buffer `out`, which must be at
index 9e163d5..2505de1 100644 (file)
@@ -898,7 +898,7 @@ static void show_combined_header(struct combine_diff_path *elem,
                                 int show_file_header)
 {
        struct diff_options *opt = &rev->diffopt;
-       int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
+       int abbrev = opt->flags.full_index ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
        const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
        const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
        const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
@@ -987,7 +987,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        userdiff = userdiff_find_by_path(elem->path);
        if (!userdiff)
                userdiff = userdiff_find_by_name("default");
-       if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV))
+       if (opt->flags.allow_textconv)
                textconv = userdiff_get_textconv(userdiff);
 
        /* Read the result of merge first */
@@ -1014,7 +1014,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        elem->mode = canon_mode(st.st_mode);
                } else if (S_ISDIR(st.st_mode)) {
                        struct object_id oid;
-                       if (resolve_gitlink_ref(elem->path, "HEAD", oid.hash) < 0)
+                       if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
                                result = grab_blob(&elem->oid, elem->mode,
                                                   &result_size, NULL, NULL);
                        else
@@ -1413,8 +1413,8 @@ void diff_tree_combined(const struct object_id *oid,
 
        diffopts = *opt;
        copy_pathspec(&diffopts.pathspec, &opt->pathspec);
-       DIFF_OPT_SET(&diffopts, RECURSIVE);
-       DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
+       diffopts.flags.recursive = 1;
+       diffopts.flags.allow_external = 0;
 
        /* find set of paths that everybody touches
         *
@@ -1435,7 +1435,7 @@ void diff_tree_combined(const struct object_id *oid,
         * NOTE please keep this semantically in sync with diffcore_std()
         */
        need_generic_pathscan = opt->skip_stat_unmatch  ||
-                       DIFF_OPT_TST(opt, FOLLOW_RENAMES)       ||
+                       opt->flags.follow_renames       ||
                        opt->break_opt != -1    ||
                        opt->detect_rename      ||
                        opt->pickaxe            ||
index 1e0e633..cab8d44 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1090,6 +1090,13 @@ struct commit_list *reduce_heads(struct commit_list *heads)
        return result;
 }
 
+void reduce_heads_replace(struct commit_list **heads)
+{
+       struct commit_list *result = reduce_heads(*heads);
+       free_commit_list(*heads);
+       *heads = result;
+}
+
 static const char gpg_sig_header[] = "gpgsig";
 static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
 
index 6d76959..99a3fea 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -313,7 +313,23 @@ extern int interactive_add(int argc, const char **argv, const char *prefix, int
 extern int run_add_interactive(const char *revision, const char *patch_mode,
                               const struct pathspec *pathspec);
 
-struct commit_list *reduce_heads(struct commit_list *heads);
+/*
+ * Takes a list of commits and returns a new list where those
+ * have been removed that can be reached from other commits in
+ * the list. It is useful for, e.g., reducing the commits
+ * randomly thrown at the git-merge command and removing
+ * redundant commits that the user shouldn't have given to it.
+ *
+ * This function destroys the STALE bit of the commit objects'
+ * flags.
+ */
+extern struct commit_list *reduce_heads(struct commit_list *heads);
+
+/*
+ * Like `reduce_heads()`, except it replaces the list. Use this
+ * instead of `foo = reduce_heads(foo);` to avoid memory leaks.
+ */
+extern void reduce_heads_replace(struct commit_list **heads);
 
 struct commit_extra_header {
        struct commit_extra_header *next;
index e276ccd..4d1d95b 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "git-compat-util.h"
 #include <gettext.h>
index ceb4bdb..6bc24b7 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 /* Summary:
 
index ae03b74..7ed3fbb 100644 (file)
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 /* Tell gcc not to warn about the (nfd < 0) tests, below.  */
 #if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
index b7aa59d..cd19952 100644 (file)
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #ifndef _GL_POLL_H
 #define _GL_POLL_H
index d8bde06..51cd60b 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
                                          size_t length, reg_syntax_t syntax);
index 5cb23e5..f3e03a9 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
index 61c9683..4d81358 100644 (file)
@@ -18,9 +18,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #ifndef _REGEX_H
 #define _REGEX_H 1
index 98342b8..59bf151 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 static void re_string_construct_common (const char *str, int len,
                                        re_string_t *pstr,
index 4184d7f..3ee8aae 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #ifndef _REGEX_INTERNAL_H
 #define _REGEX_INTERNAL_H 1
index 6f2b48a..1b5d89f 100644 (file)
@@ -14,9 +14,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
                                     int n) internal_function;
index adb7d7a..903abf9 100644 (file)
--- a/config.c
+++ b/config.c
@@ -2751,7 +2751,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
 {
        int ret = 0, remove = 0;
        char *filename_buf = NULL;
-       struct lock_file *lock;
+       struct lock_file lock = LOCK_INIT;
        int out_fd;
        char buf[1024];
        FILE *config_file = NULL;
@@ -2766,8 +2766,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
        if (!config_filename)
                config_filename = filename_buf = git_pathdup("config");
 
-       lock = xcalloc(1, sizeof(struct lock_file));
-       out_fd = hold_lock_file_for_update(lock, config_filename, 0);
+       out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
        if (out_fd < 0) {
                ret = error("could not lock config file %s", config_filename);
                goto out;
@@ -2786,9 +2785,9 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
                goto out;
        }
 
-       if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
+       if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
                ret = error_errno("chmod on %s failed",
-                                 get_lock_file_path(lock));
+                                 get_lock_file_path(&lock));
                goto out;
        }
 
@@ -2812,7 +2811,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
                         */
                        if (copystr.len > 0) {
                                if (write_in_full(out_fd, copystr.buf, copystr.len) != copystr.len) {
-                                       ret = write_error(get_lock_file_path(lock));
+                                       ret = write_error(get_lock_file_path(&lock));
                                        goto out;
                                }
                                strbuf_reset(&copystr);
@@ -2828,7 +2827,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
                                store.baselen = strlen(new_name);
                                if (!copy) {
                                        if (write_section(out_fd, new_name) < 0) {
-                                               ret = write_error(get_lock_file_path(lock));
+                                               ret = write_error(get_lock_file_path(&lock));
                                                goto out;
                                        }
                                        /*
@@ -2862,7 +2861,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
                }
 
                if (write_in_full(out_fd, output, length) < 0) {
-                       ret = write_error(get_lock_file_path(lock));
+                       ret = write_error(get_lock_file_path(&lock));
                        goto out;
                }
        }
@@ -2874,7 +2873,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
         */
        if (copystr.len > 0) {
                if (write_in_full(out_fd, copystr.buf, copystr.len) != copystr.len) {
-                       ret = write_error(get_lock_file_path(lock));
+                       ret = write_error(get_lock_file_path(&lock));
                        goto out;
                }
                strbuf_reset(&copystr);
@@ -2883,13 +2882,13 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
        fclose(config_file);
        config_file = NULL;
 commit_and_out:
-       if (commit_lock_file(lock) < 0)
+       if (commit_lock_file(&lock) < 0)
                ret = error_errno("could not write config file %s",
                                  config_filename);
 out:
        if (config_file)
                fclose(config_file);
-       rollback_lock_file(lock);
+       rollback_lock_file(&lock);
 out_no_rollback:
        free(filename_buf);
        return ret;
index f416b05..4a47f33 100644 (file)
  *
  * Returns 0 if everything is connected, non-zero otherwise.
  */
-int check_connected(sha1_iterate_fn fn, void *cb_data,
+int check_connected(oid_iterate_fn fn, void *cb_data,
                    struct check_connected_options *opt)
 {
        struct child_process rev_list = CHILD_PROCESS_INIT;
        struct check_connected_options defaults = CHECK_CONNECTED_INIT;
-       char commit[41];
-       unsigned char sha1[20];
+       char commit[GIT_MAX_HEXSZ + 1];
+       struct object_id oid;
        int err = 0;
        struct packed_git *new_pack = NULL;
        struct transport *transport;
@@ -32,7 +32,7 @@ int check_connected(sha1_iterate_fn fn, void *cb_data,
                opt = &defaults;
        transport = opt->transport;
 
-       if (fn(cb_data, sha1)) {
+       if (fn(cb_data, &oid)) {
                if (opt->err_fd)
                        close(opt->err_fd);
                return err;
@@ -77,7 +77,7 @@ int check_connected(sha1_iterate_fn fn, void *cb_data,
 
        sigchain_push(SIGPIPE, SIG_IGN);
 
-       commit[40] = '\n';
+       commit[GIT_SHA1_HEXSZ] = '\n';
        do {
                /*
                 * If index-pack already checked that:
@@ -87,17 +87,17 @@ int check_connected(sha1_iterate_fn fn, void *cb_data,
                 * are sure the ref is good and not sending it to
                 * rev-list for verification.
                 */
-               if (new_pack && find_pack_entry_one(sha1, new_pack))
+               if (new_pack && find_pack_entry_one(oid.hash, new_pack))
                        continue;
 
-               memcpy(commit, sha1_to_hex(sha1), 40);
-               if (write_in_full(rev_list.in, commit, 41) < 0) {
+               memcpy(commit, oid_to_hex(&oid), GIT_SHA1_HEXSZ);
+               if (write_in_full(rev_list.in, commit, GIT_SHA1_HEXSZ + 1) < 0) {
                        if (errno != EPIPE && errno != EINVAL)
                                error_errno(_("failed write to rev-list"));
                        err = -1;
                        break;
                }
-       } while (!fn(cb_data, sha1));
+       } while (!fn(cb_data, &oid));
 
        if (close(rev_list.in))
                err = error_errno(_("failed to close rev-list's stdin"));
index 4ca325f..a53f03a 100644 (file)
@@ -8,7 +8,7 @@ struct transport;
  * When called after returning the name for the last object, return -1
  * to signal EOF, otherwise return 0.
  */
-typedef int (*sha1_iterate_fn)(void *, unsigned char [20]);
+typedef int (*oid_iterate_fn)(void *, struct object_id *oid);
 
 /*
  * Named-arguments struct for check_connected. All arguments are
@@ -51,7 +51,7 @@ struct check_connected_options {
  *
  * If "opt" is NULL, behaves as if CHECK_CONNECTED_INIT was passed.
  */
-int check_connected(sha1_iterate_fn fn, void *cb_data,
+int check_connected(oid_iterate_fn fn, void *cb_data,
                    struct check_connected_options *opt);
 
 #endif /* CONNECTED_H */
index 539d7f8..f07f16b 100644 (file)
@@ -111,8 +111,7 @@ __git ()
 #   GNU General Public License for more details.
 #
 #   You should have received a copy of the GNU General Public License
-#   along with this program; if not, write to the Free Software Foundation,
-#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#   along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 #   The latest version of this software can be obtained here:
 #
@@ -2351,6 +2350,7 @@ _git_config ()
                advice.rmHints
                advice.statusHints
                advice.statusUoption
+               advice.ignoredHook
                alias.
                am.keepcr
                am.threeWay
index 2a317fc..d389bfa 100644 (file)
@@ -13,8 +13,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
index b4750c9..e6598b6 100644 (file)
@@ -14,8 +14,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
index e671f6c..510e0f7 100644 (file)
@@ -25,9 +25,8 @@
 ;; PURPOSE.  See the GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public
-;; License along with this program; if not, write to the Free
-;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-;; MA 02111-1307 USA
+;; License along with this program; if not, see
+;; <http://www.gnu.org/licenses/>.
 
 ;; http://www.fsf.org/copyleft/gpl.html
 
index 5ffc506..97919f2 100644 (file)
@@ -15,9 +15,8 @@
 ;; PURPOSE.  See the GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public
-;; License along with this program; if not, write to the Free
-;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-;; MA 02111-1307 USA
+;; License along with this program; if not, see
+;; <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
index 4dec1f1..a16f79c 100755 (executable)
@@ -14,8 +14,7 @@
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # ------------------------------------------------------------------------
 
index 60dec86..de3f816 100755 (executable)
@@ -15,8 +15,7 @@
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    along with this program; if not, see <http://www.gnu.org/licenses/>.
 """
 
 import os, os.path, sys
index d13c4df..917d9e2 100644 (file)
@@ -2,6 +2,7 @@ package Git::Mediawiki;
 
 use 5.008;
 use strict;
+use POSIX;
 use Git;
 
 BEGIN {
@@ -52,7 +53,7 @@ sub smudge_filename {
        $filename =~ s/ /_/g;
        # Decode forbidden characters encoded in clean_filename
        $filename =~ s/_%_([0-9a-fA-F][0-9a-fA-F])/sprintf('%c', hex($1))/ge;
-       return $filename;
+       return substr($filename, 0, NAME_MAX-length('.mw'));
 }
 
 sub connect_maybe {
index e7f857c..af9cbc9 100755 (executable)
@@ -63,6 +63,11 @@ chomp(@tracked_pages);
 my @tracked_categories = split(/[ \n]/, run_git("config --get-all remote.${remotename}.categories"));
 chomp(@tracked_categories);
 
+# Just like @tracked_categories, but for MediaWiki namespaces.
+my @tracked_namespaces = split(/[ \n]/, run_git("config --get-all remote.${remotename}.namespaces"));
+for (@tracked_namespaces) { s/_/ /g; }
+chomp(@tracked_namespaces);
+
 # Import media files on pull
 my $import_media = run_git("config --get --bool remote.${remotename}.mediaimport");
 chomp($import_media);
@@ -256,6 +261,32 @@ sub get_mw_tracked_categories {
        return;
 }
 
+sub get_mw_tracked_namespaces {
+    my $pages = shift;
+    foreach my $local_namespace (sort @tracked_namespaces) {
+        my $namespace_id;
+        if ($local_namespace eq "(Main)") {
+            $namespace_id = 0;
+        } else {
+            $namespace_id = get_mw_namespace_id($local_namespace);
+        }
+        # virtual namespaces don't support allpages
+        next if !defined($namespace_id) || $namespace_id < 0;
+        my $mw_pages = $mediawiki->list( {
+            action => 'query',
+            list => 'allpages',
+            apnamespace => $namespace_id,
+            aplimit => 'max' } )
+            || die $mediawiki->{error}->{code} . ': '
+                . $mediawiki->{error}->{details} . "\n";
+        print {*STDERR} "$#{$mw_pages} found in namespace $local_namespace ($namespace_id)\n";
+        foreach my $page (@{$mw_pages}) {
+            $pages->{$page->{title}} = $page;
+        }
+    }
+    return;
+}
+
 sub get_mw_all_pages {
        my $pages = shift;
        # No user-provided list, get the list of pages from the API.
@@ -319,6 +350,10 @@ sub get_mw_pages {
                $user_defined = 1;
                get_mw_tracked_categories(\%pages);
        }
+       if (@tracked_namespaces) {
+               $user_defined = 1;
+               get_mw_tracked_namespaces(\%pages);
+       }
        if (!$user_defined) {
                get_mw_all_pages(\%pages);
        }
@@ -1308,7 +1343,8 @@ sub get_mw_namespace_id {
        my $id;
 
        if (!defined $ns) {
-               print {*STDERR} "No such namespace ${name} on MediaWiki.\n";
+               my @namespaces = map { s/ /_/g; $_; } sort keys %namespace_id;
+               print {*STDERR} "No such namespace ${name} on MediaWiki, known namespaces: @namespaces\n";
                $ns = {is_namespace => 0};
                $namespace_id{$name} = $ns;
        }
index 4e0980c..731f088 100644 (file)
@@ -36,7 +36,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
        if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
                return 1;
        if (S_ISDIR(st->st_mode)) {
-               unsigned char sub[20];
+               struct object_id sub;
 
                /*
                 * If ce is already a gitlink, we can have a plain
@@ -50,7 +50,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
                 * a directory --- the blob was removed!
                 */
                if (!S_ISGITLINK(ce->ce_mode) &&
-                   resolve_gitlink_ref(ce->name, "HEAD", sub))
+                   resolve_gitlink_ref(ce->name, "HEAD", &sub))
                        return 1;
        }
        return 0;
@@ -71,14 +71,15 @@ static int match_stat_with_submodule(struct diff_options *diffopt,
 {
        int changed = ce_match_stat(ce, st, ce_option);
        if (S_ISGITLINK(ce->ce_mode)) {
-               unsigned orig_flags = diffopt->flags;
-               if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))
+               struct diff_flags orig_flags = diffopt->flags;
+               if (!diffopt->flags.override_submodule_config)
                        set_diffopt_flags_from_submodule_config(diffopt, ce->name);
-               if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))
+               if (diffopt->flags.ignore_submodules)
                        changed = 0;
-               else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)
-                   && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))
-                       *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));
+               else if (!diffopt->flags.ignore_dirty_submodules &&
+                        (!changed || diffopt->flags.dirty_submodules))
+                       *dirty_submodule = is_submodule_modified(ce->name,
+                                                                diffopt->flags.ignore_untracked_in_submodules);
                diffopt->flags = orig_flags;
        }
        return changed;
@@ -228,7 +229,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 
                if (!changed && !dirty_submodule) {
                        ce_mark_uptodate(ce);
-                       if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+                       if (!revs->diffopt.flags.find_copies_harder)
                                continue;
                }
                oldmode = ce->ce_mode;
@@ -362,7 +363,7 @@ static int show_modified(struct rev_info *revs,
 
        oldmode = old->ce_mode;
        if (mode == oldmode && !oidcmp(oid, &old->oid) && !dirty_submodule &&
-           !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+           !revs->diffopt.flags.find_copies_harder)
                return 0;
 
        diff_change(&revs->diffopt, oldmode, mode,
@@ -493,7 +494,7 @@ static int diff_cache(struct rev_info *revs,
        opts.head_idx = 1;
        opts.index_only = cached;
        opts.diff_index_cached = (cached &&
-                                 !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER));
+                                 !revs->diffopt.flags.find_copies_harder);
        opts.merge = 1;
        opts.fn = oneway_diff;
        opts.unpack_data = revs;
@@ -534,7 +535,7 @@ int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
        return 0;
 }
 
-int index_differs_from(const char *def, int diff_flags,
+int index_differs_from(const char *def, const struct diff_flags *flags,
                       int ita_invisible_in_index)
 {
        struct rev_info rev;
@@ -544,11 +545,12 @@ int index_differs_from(const char *def, int diff_flags,
        memset(&opt, 0, sizeof(opt));
        opt.def = def;
        setup_revisions(0, NULL, &rev, &opt);
-       DIFF_OPT_SET(&rev.diffopt, QUICK);
-       DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
-       rev.diffopt.flags |= diff_flags;
+       rev.diffopt.flags.quick = 1;
+       rev.diffopt.flags.exit_with_status = 1;
+       if (flags)
+               diff_flags_or(&rev.diffopt.flags, flags);
        rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
        run_diff_index(&rev, 1);
        object_array_clear(&rev.pending);
-       return (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0);
+       return (rev.diffopt.flags.has_changes != 0);
 }
index 80ff17d..0ed5f0f 100644 (file)
@@ -184,7 +184,7 @@ static int queue_diff(struct diff_options *o,
        } else {
                struct diff_filespec *d1, *d2;
 
-               if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+               if (o->flags.reverse_diff) {
                        SWAP(mode1, mode2);
                        SWAP(name1, name2);
                }
@@ -276,16 +276,16 @@ void diff_no_index(struct rev_info *revs,
        if (!revs->diffopt.output_format)
                revs->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-       DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
+       revs->diffopt.flags.no_index = 1;
 
-       DIFF_OPT_SET(&revs->diffopt, RELATIVE_NAME);
+       revs->diffopt.flags.relative_name = 1;
        revs->diffopt.prefix = prefix;
 
        revs->max_count = -2;
        diff_setup_done(&revs->diffopt);
 
        setup_diff_pager(&revs->diffopt);
-       DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
+       revs->diffopt.flags.exit_with_status = 1;
 
        if (queue_diff(&revs->diffopt, paths[0], paths[1]))
                exit(1);
diff --git a/diff.c b/diff.c
index 1898dd3..0763e89 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -124,18 +124,18 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
        for (i = 0; i < params.nr; i++) {
                const char *p = params.items[i].string;
                if (!strcmp(p, "changes")) {
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
+                       options->flags.dirstat_by_line = 0;
+                       options->flags.dirstat_by_file = 0;
                } else if (!strcmp(p, "lines")) {
-                       DIFF_OPT_SET(options, DIRSTAT_BY_LINE);
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
+                       options->flags.dirstat_by_line = 1;
+                       options->flags.dirstat_by_file = 0;
                } else if (!strcmp(p, "files")) {
-                       DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
-                       DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
+                       options->flags.dirstat_by_line = 0;
+                       options->flags.dirstat_by_file = 1;
                } else if (!strcmp(p, "noncumulative")) {
-                       DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
+                       options->flags.dirstat_cumulative = 0;
                } else if (!strcmp(p, "cumulative")) {
-                       DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
+                       options->flags.dirstat_cumulative = 1;
                } else if (isdigit(*p)) {
                        char *end;
                        int permille = strtoul(p, &end, 10) * 10;
@@ -1412,7 +1412,7 @@ static void emit_rewrite_diff(const char *name_a,
        struct emit_callback ecbdata;
        struct strbuf out = STRBUF_INIT;
 
-       if (diff_mnemonic_pre