Merge branch 'pc/remove-warn' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 22 Jun 2010 15:30:38 +0000 (08:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 22 Jun 2010 15:30:38 +0000 (08:30 -0700)
* pc/remove-warn:
  Remove a redundant errno test in a usage of remove_path
  Introduce remove_or_warn function
  Implement the rmdir_or_warn function
  Generalise the unlink_or_warn function

226 files changed:
.gitignore
.mailmap
Documentation/Makefile
Documentation/RelNotes-1.7.0.4.txt [new file with mode: 0644]
Documentation/RelNotes-1.7.0.5.txt [new file with mode: 0644]
Documentation/RelNotes-1.7.0.6.txt [new file with mode: 0644]
Documentation/RelNotes-1.7.1.1.txt [new file with mode: 0644]
Documentation/RelNotes-1.7.1.txt
Documentation/SubmittingPatches
Documentation/blame-options.txt
Documentation/config.txt
Documentation/diff-options.txt
Documentation/everyday.txt
Documentation/git-add.txt
Documentation/git-branch.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-commit.txt
Documentation/git-fetch.txt
Documentation/git-http-backend.txt
Documentation/git-imap-send.txt
Documentation/git-log.txt
Documentation/git-mailinfo.txt
Documentation/git-merge.txt
Documentation/git-notes.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-remote-helpers.txt
Documentation/git-send-email.txt
Documentation/git-shortlog.txt
Documentation/git-show-ref.txt
Documentation/git-status.txt
Documentation/git-update-index.txt
Documentation/git.txt
Documentation/gitdiffcore.txt
Documentation/gitignore.txt
Documentation/howto/revert-a-faulty-merge.txt
Documentation/merge-options.txt
Documentation/pretty-formats.txt
Documentation/pretty-options.txt
Documentation/technical/api-string-list.txt
Documentation/technical/pack-protocol.txt
Documentation/urls.txt
GIT-VERSION-GEN
Makefile
RelNotes
attr.c
branch.c
builtin/apply.c
builtin/blame.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/describe.c
builtin/fast-export.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/grep.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/mailinfo.c
builtin/merge-file.c
builtin/merge-tree.c
builtin/merge.c
builtin/notes.c
builtin/pack-objects.c
builtin/push.c
builtin/reflog.c
builtin/rerere.c
builtin/reset.c
builtin/rev-list.c
builtin/revert.c
builtin/shortlog.c
builtin/show-branch.c
builtin/tag.c
cache.h
combine-diff.c
commit.h
compat/bswap.h
compat/mingw.c
compat/mingw.h
compat/vcbuild/include/termios.h [new file with mode: 0644]
compat/win32/pthread.h
compat/win32mmap.c
config.mak.in
configure.ac
contrib/ciabot/README [new file with mode: 0644]
contrib/ciabot/ciabot.py [new file with mode: 0755]
contrib/ciabot/ciabot.sh [new file with mode: 0755]
contrib/completion/git-completion.bash
contrib/fast-import/import-zips.py
contrib/hg-to-git/hg-to-git.py
contrib/hooks/post-receive-email
contrib/p4import/git-p4import.py
daemon.c
date.c
diff-no-index.c
diff.c
dir.c
exec_cmd.c
git-add--interactive.perl
git-am.sh
git-compat-util.h
git-difftool.perl
git-instaweb.sh
git-pull.sh
git-rebase--interactive.sh
git-rebase.sh
git-send-email.perl
git-stash.sh
git-submodule.sh
git.spec.in
git_remote_helpers/Makefile
gitk-git/gitk
gitk-git/po/de.po
gitk-git/po/es.po
gitk-git/po/fr.po
gitk-git/po/hu.po
gitk-git/po/it.po
gitk-git/po/ja.po
gitk-git/po/ru.po
gitk-git/po/sv.po
gitweb/INSTALL
gitweb/Makefile
gitweb/README
gitweb/gitweb.perl
grep.c
http-backend.c
http-walker.c
http.c
http.h
imap-send.c
ll-merge.c
ll-merge.h
merge-file.c
merge-recursive.c
merge-recursive.h
notes.h
object.c
pack-check.c
pack.h
parse-options.c
parse-options.h
pretty.c
refs.c
remote-curl.c
remote.c
rerere.c
run-command.c
setup.c
sha1_file.c
shortlog.h
string-list.c
string-list.h
submodule.c
t/README
t/lib-t6000.sh [moved from t/t6000lib.sh with 100% similarity]
t/t0000-basic.sh
t/t0001-init.sh
t/t0003-attributes.sh
t/t1010-mktree.sh
t/t1304-default-acl.sh
t/t1501-worktree.sh
t/t2007-checkout-symlink.sh
t/t2106-update-index-assume-unchanged.sh [new file with mode: 0755]
t/t3301-notes.sh
t/t3307-notes-man.sh [new file with mode: 0755]
t/t3404-rebase-interactive.sh
t/t3506-cherry-pick-ff.sh [new file with mode: 0755]
t/t3507-cherry-pick-conflict.sh [new file with mode: 0755]
t/t3903-stash.sh
t/t4014-format-patch.sh
t/t4017-diff-retval.sh
t/t4038-diff-combined.sh
t/t4041-diff-submodule.sh
t/t4124-apply-ws-rule.sh
t/t4201-shortlog.sh
t/t5407-post-rewrite-hook.sh
t/t5505-remote.sh
t/t5516-fetch-push.sh
t/t5541-http-push.sh
t/t5550-http-fetch.sh
t/t5601-clone.sh
t/t5704-bundle.sh
t/t5705-clone-2gb.sh
t/t6002-rev-list-bisect.sh
t/t6003-rev-list-topo-order.sh
t/t6006-rev-list-format.sh
t/t6023-merge-file.sh
t/t6101-rev-parse-parents.sh
t/t6120-describe.sh
t/t6200-fmt-merge-msg.sh
t/t7005-editor.sh
t/t7006-pager.sh
t/t7012-skip-worktree-writing.sh
t/t7201-co.sh
t/t7502-commit.sh
t/t7506-status-submodule.sh
t/t7508-status.sh
t/t7800-difftool.sh
t/t9350-fast-export.sh
t/test-lib.sh
tag.c
tag.h
templates/Makefile
templates/hooks--commit-msg.sample
templates/hooks--post-update.sample
templates/hooks--pre-commit.sample
templates/hooks--pre-rebase.sample
templates/hooks--prepare-commit-msg.sample
templates/hooks--update.sample
templates/info--exclude
thread-utils.c
thread-utils.h
unpack-trees.c
userdiff.c
wrapper.c
wt-status.c
xdiff-interface.c
xdiff-interface.h
xdiff/xdiff.h
xdiff/xmerge.c

index 7b3acb7..dbf1b90 100644 (file)
 /git-write-tree
 /git-core-*/?*
 /gitk-git/gitk-wish
+/gitweb/GITWEB-BUILD-OPTIONS
 /gitweb/gitweb.cgi
+/gitweb/gitweb.min.*
 /test-chmtime
 /test-ctype
 /test-date
 *.exe
 *.[aos]
 *.py[co]
-*.o.d
+.depend/
 *+
 /config.mak
 /autom4te.cache
index 88bd01e..a8091eb 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -5,6 +5,7 @@
 # same person appearing not to be so.
 #
 
+Alex Bennée <kernel-hacker@bennee.com>
 Alexander Gavrilov <angavrilov@gmail.com>
 Aneesh Kumar K.V <aneesh.kumar@gmail.com>
 Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
@@ -15,6 +16,7 @@ Daniel Barkalow <barkalow@iabervon.org>
 David D. Kilzer <ddkilzer@kilzer.net>
 David Kågedal <davidk@lysator.liu.se>
 David S. Miller <davem@davemloft.net>
+Deskin Miller <deskinm@umich.edu>
 Dirk Süsserott <newsletter@dirk.my1.cc>
 Fredrik Kuivinen <freku045@student.liu.se>
 H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
@@ -60,6 +62,7 @@ Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
 Uwe Kleine-König <uzeisberger@io.fsforth.de>
 Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
 Ville Skyttä <scop@xemacs.org>
+Vitaly "_Vi" Shukela <public_vi@tut.by>
 William Pursell <bill.pursell@gmail.com>
 YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
 anonymous <linux@horizon.com>
index 8a8a395..04f69cf 100644 (file)
@@ -264,7 +264,9 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
        mv $@+ $@
 
 user-manual.xml: user-manual.txt user-manual.conf
-       $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book $<
+       $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+       $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book -o $@+ $< && \
+       mv $@+ $@
 
 technical/api-index.txt: technical/api-index-skel.txt \
        technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
@@ -278,7 +280,9 @@ XSLT = docbook.xsl
 XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
 
 user-manual.html: user-manual.xml
-       $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
+       $(QUIET_XSLTPROC)$(RM) $@+ $@ && \
+       xsltproc $(XSLTOPTS) -o $@+ $(XSLT) $< && \
+       mv $@+ $@
 
 git.info: user-manual.texi
        $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
diff --git a/Documentation/RelNotes-1.7.0.4.txt b/Documentation/RelNotes-1.7.0.4.txt
new file mode 100644 (file)
index 0000000..cf7f60e
--- /dev/null
@@ -0,0 +1,27 @@
+Git v1.7.0.4 Release Notes
+==========================
+
+Fixes since v1.7.0.3
+--------------------
+
+ * Optimized ntohl/htonl on big-endian machines were broken.
+
+ * Color values given to "color.<cmd>.<slot>" configuration can now have
+   more than one attributes (e.g. "bold ul").
+
+ * "git add -u nonexistent-path" did not complain.
+
+ * "git apply --whitespace=fix" didn't work well when an early patch in
+   a patch series adds trailing blank lines and a later one depended on
+   such a block of blank lines at the end.
+
+ * "git fast-export" didn't check error status and stop when marks file
+   cannot be opened.
+
+ * "git format-patch --ignore-if-in-upstream" gave unwarranted errors
+   when the range was empty, instead of silently finishing.
+
+ * "git remote prune" did not detect remote tracking refs that became
+   dangling correctly.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.0.5.txt b/Documentation/RelNotes-1.7.0.5.txt
new file mode 100644 (file)
index 0000000..3149c91
--- /dev/null
@@ -0,0 +1,26 @@
+Git v1.7.0.5 Release Notes
+==========================
+
+Fixes since v1.7.0.4
+--------------------
+
+ * "git daemon" failed to compile on platforms without sockaddr_storage type.
+
+ * Output from "git rev-list --pretty=oneline" was unparsable when a
+   commit did not have any message, which is abnormal but possible in a
+   repository converted from foreign scm.
+
+ * "git stash show <commit-that-is-not-a-stash>" gave an error message
+   that was not so useful.  Reworded the message to "<it> is not a
+   stash".
+
+ * Python scripts in contrib/ area now start with "#!/usr/bin/env python"
+   to honor user's PATH.
+
+ * "git imap-send" used to mistake any line that begins with "From " as a
+   message separator in format-patch output.
+
+ * Smart http server backend failed to report an internal server error and
+   infinitely looped instead after output pipe was closed.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.0.6.txt b/Documentation/RelNotes-1.7.0.6.txt
new file mode 100644 (file)
index 0000000..b2852b6
--- /dev/null
@@ -0,0 +1,13 @@
+Git v1.7.0.6 Release Notes
+==========================
+
+Fixes since v1.7.0.5
+--------------------
+
+ * "git diff --stat" used "int" to count the size of differences,
+   which could result in overflowing.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+   newer tools in the git toolset.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.1.1.txt b/Documentation/RelNotes-1.7.1.1.txt
new file mode 100644 (file)
index 0000000..e0386a4
--- /dev/null
@@ -0,0 +1,67 @@
+Git v1.7.1.1 Release Notes (draft)
+==================================
+
+Fixes since v1.7.1
+------------------
+
+ * Authentication over http transport can now be made lazily, in that the
+   request can first go to a URL without username, get a 401 response and
+   then the client will ask for the username to use.
+
+ * We used to mistakenly think "../work" is a subdirectory of the current
+   directory when we are in "../work-xyz".
+
+ * The attribute mechanism now allows an entry that uses an attribute
+   macro that set/unset one attribute, immediately followed by an
+   overriding setting; this makes attribute macros much easier to use.
+
+ * We didn't recognize timezone "Z" as a synonym for "UTC" (75b37e70).
+
+ * "git am -3" did not show diagnosis when the patch in the message was corrupt.
+
+ * After "git apply --whitespace=fix" removed trailing blank lines in an
+   patch in a patch series, it failed to apply later patches that depend
+   on the presense of such blank lines.
+
+ * "git bundle --stdin" segfaulted.
+
+ * "git checkout" and "git rebase" overwrote paths that are marked "assume
+   unchanged".
+
+ * "git describe" did not tie-break tags that point at the same commit
+   correctly; newer ones are preferred by paying attention to the
+   tagger date now.
+
+ * "git diff" used to tell underlying xdiff machinery to work very hard to
+   minimize the output, but this often was spending too many extra cycles
+   for very little gain.
+
+ * "git diff --color" did not paint extended diff headers per line
+   (i.e. the coloring escape sequence didn't end at the end of line),
+   which confused "less -R".
+
+ * "git fetch" over HTTP verifies the downloaded packfiles more robustly.
+
+ * The memory usage by "git index-pack" (run during "git fetch" and "git
+   push") got leaner.
+
+ * "GIT_DIR=foo.git git init --bare bar.git" created foo.git instead of bar.git.
+
+ * "git log --abbrev=$num --format='%h' ignored --abbrev=$num.
+
+ * "git pull" accepted "--dry-run", gave it to underlying "git fetch" but
+   ignored the option itself, resulting in a bogus attempt to merge
+   unrelated commit.
+
+ * "git send-email" lacked a way to specify the domainname used in the
+   EHLO/HELO exchange, causing rejected connection from picky servers.
+   It learned --smtp-domain option to solve this issue.
+
+ * "git stash" incorrectly lost paths in the working tree that were
+   previously removed from the index.
+
+ * "git status" stopped refreshing the index by mistake in 1.7.1.
+
+ * "git status" showed excess "hints" even when advice.statusHints is set to false.
+
+And other minor fixes and documentation updates.
index 750d40f..9d89fed 100644 (file)
@@ -1,25 +1,31 @@
-Git v1.7.1 Release Notes (draft)
-================================
+Git v1.7.1 Release Notes
+========================
 
 Updates since v1.7.0
 --------------------
 
+ * Eric Raymond is the maintainer of updated CIAbot scripts, in contrib/.
+
+ * gitk updates.
+
  * Some commands (e.g. svn and http interfaces) that interactively ask
-   password can be told to use an external program given via GIT_ASKPASS.
+   for a password can be told to use an external program given via
+   GIT_ASKPASS.
 
- * Color values given to "color.<cmd>.<slot>" configuration can now have
-   more than one attributes (e.g. "bold ul").
+ * Conflict markers that lead the common ancestor in diff3-style output
+   now have a label, which hopefully would help third-party tools that
+   expect one.
 
- * "git apply --whitespace=fix" didn't work well when an early patch in
-   a patch series adds trailing blank lines and a later one depended on
-   such a block of blank lines at the end.
+ * Comes with an updated bash-completion script.
 
  * "git am" learned "--keep-cr" option to handle inputs that are
-   mixture of changes to files with and without CRLF line endings.
+   mixture of changes to files with and without CRLF line endings.
 
  * "git cvsimport" learned -R option to leave revision mapping between
    CVS revisions and resulting git commits.
 
+ * "git diff --submodule" notices and describes dirty submodules.
+
  * "git for-each-ref" learned %(symref), %(symref:short) and %(flag)
    tokens.
 
@@ -36,11 +42,14 @@ Updates since v1.7.0
 
  * "git grep" learned to paint filename and line-number in colors.
 
- * "git merge-file" learned to use custom conflict marker size and also use
-   the "union merge" behaviour.
+ * "git log -p --first-parent -m" shows one-parent diff for merge
+   commits, instead of showing combined diff.
 
- * "git notes" command has been rewritten in C and learned quite a
-   many commands.
+ * "git merge-file" learned to use custom conflict marker size and also
+   to use the "union merge" behaviour.
+
+ * "git notes" command has been rewritten in C and learned many commands
+   and features to help you carry notes forward across rebases and amends.
 
  * "git request-pull" identifies the commit the request is relative to in
    a more readable way.
@@ -49,11 +58,18 @@ Updates since v1.7.0
    near the tip while preserving your local changes in a way similar
    to how "git checkout branch" does.
 
+ * "git status" notices and describes dirty submodules.
+
  * "git svn" should work better when interacting with repositories
    with CRLF line endings.
 
  * "git imap-send" learned to support CRAM-MD5 authentication.
 
+ * "gitweb" installation procedure can use "minified" js/css files
+   better.
+
+ * Various documentation updates.
+
 Fixes since v1.7.0
 ------------------
 
@@ -63,8 +79,11 @@ release, unless otherwise noted.
  * "git add frotz/nitfol" did not complain when the entire frotz/ directory
    was ignored.
 
----
-exec >/var/tmp/1
-echo O=$(git describe)
-O=v1.7.0.2-323-g0d0925c
-git shortlog --no-merges ^maint $O..
+ * "git diff --stat" used "int" to count the size of differences,
+   which could result in overflowing.
+
+ * "git rev-list --pretty=oneline" didn't terminate a record with LF for
+   commits without any message.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+   newer tools in the git toolset.
index c686f86..eb53e06 100644 (file)
@@ -41,6 +41,7 @@ Checklist (and a short version for the impatient):
          maintainer (gitster@pobox.com) if (and only if) the patch
          is ready for inclusion. If you use git-send-email(1),
          please test it first by sending email to yourself.
+       - see below for instructions specific to your mailer
 
 Long version:
 
@@ -53,6 +54,34 @@ But the patch submission requirements are a lot more relaxed
 here on the technical/contents front, because the core GIT is
 thousand times smaller ;-).  So here is only the relevant bits.
 
+(0) 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 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.
+
+ - 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.
+
+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.
 
@@ -170,17 +199,16 @@ patch, format it as "multipart/signed", not a text/plain message
 that starts with '-----BEGIN PGP SIGNED MESSAGE-----'.  That is
 not a text/plain, it's something else.
 
-Note that your maintainer does not necessarily read everything
-on the git mailing list.  If your patch is for discussion first,
-send it "To:" the mailing list, and optionally "cc:" him.  If it
-is trivially correct or after the list reached a consensus, send
-it "To:" the maintainer and optionally "cc:" the list for
-inclusion.
-
-Also note that your maintainer does not actively involve himself in
-maintaining what are in contrib/ hierarchy.  When you send fixes and
-enhancements to them, do not forget to "cc: " the person who primarily
-worked on that hierarchy in contrib/.
+Unless your patch is a very trivial and an obviously correct one,
+first send it 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
+identify them), to solicit comments and reviews.  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 and optionally "cc:" the list for
+inclusion.  Do not forget to add trailers such as "Acked-by:",
+"Reviewed-by:" and "Tested-by:" after your "Signed-off-by:" line as
+necessary.
 
 
 (4) Sign your work
@@ -519,12 +547,28 @@ Gmail
 
 GMail does not appear to have any way to turn off line wrapping in the web
 interface, so this will mangle any emails that you send.  You can however
-use any IMAP email client to connect to the google imap server, and forward
-the emails through that.  Just make sure to disable line wrapping in that
-email client.  Alternatively, use "git send-email" instead.
+use "git send-email" and send your patches through the GMail SMTP server, or
+use any IMAP email client to connect to the google IMAP server and forward
+the emails through that.
+
+To use "git send-email" and send your patches through the GMail SMTP server,
+edit ~/.gitconfig to specify your account settings:
+
+[sendemail]
+       smtpencryption = tls
+       smtpserver = smtp.gmail.com
+       smtpuser = user@gmail.com
+       smtppass = p4ssw0rd
+       smtpserverport = 587
 
-Submitting properly formatted patches via Gmail is simple now that
-IMAP support is available. First, edit your ~/.gitconfig to specify your
+Once your commits are ready to be sent to the mailing list, run the
+following commands:
+
+  $ git format-patch --cover-letter -M origin/master -o outgoing/
+  $ edit outgoing/0000-*
+  $ git send-email outgoing/*
+
+To submit using the IMAP interface, first, edit your ~/.gitconfig to specify your
 account settings:
 
 [imap]
@@ -538,14 +582,12 @@ account settings:
 You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error
 that the "Folder doesn't exist".
 
-Next, ensure that your Gmail settings are correct. In "Settings" the
-"Use Unicode (UTF-8) encoding for outgoing messages" should be checked.
-
-Once your commits are ready to send to the mailing list, run the following
-command to send the patch emails to your Gmail Drafts folder.
+Once your commits are ready to be sent to the mailing list, run the
+following commands:
 
-       $ git format-patch -M --stdout origin/master | git imap-send
+  $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
 
-Go to your Gmail account, open the Drafts folder, find the patch email, fill
-in the To: and CC: fields and send away!
+Just make sure to disable line wrapping in the email client (GMail web
+interface will line wrap no matter what, so you need to use a real
+IMAP client).
 
index 4833cac..16e3c68 100644 (file)
@@ -79,22 +79,23 @@ of lines before or after the line given by <start>.
        of the --date option at linkgit:git-log[1].
 
 -M|<num>|::
-       Detect moving lines in the file as well.  When a commit
-       moves a block of lines in a file (e.g. the original file
-       has A and then B, and the commit changes it to B and
-       then A), the traditional 'blame' algorithm typically blames
-       the lines that were moved up (i.e. B) to the parent and
-       assigns blame to the lines that were moved down (i.e. A)
-       to the child commit.  With this option, both groups of lines
-       are blamed on the parent.
+       Detect moved or copied lines within a file. When a commit
+       moves or copies a block of lines (e.g. the original file
+       has A and then B, and the commit changes it to B and then
+       A), the traditional 'blame' algorithm notices only half of
+       the movement and typically blames the lines that were moved
+       up (i.e. B) to the parent and assigns blame to the lines that
+       were moved down (i.e. A) to the child commit.  With this
+       option, both groups of lines are blamed on the parent by
+       running extra passes of inspection.
 +
 <num> is optional but it is the lower bound on the number of
-alphanumeric characters that git must detect as moving
+alphanumeric characters that git must detect as moving/copying
 within a file for it to associate those lines with the parent
-commit.
+commit. The default value is 20.
 
 -C|<num>|::
-       In addition to `-M`, detect lines copied from other
+       In addition to `-M`, detect lines moved or copied from other
        files that were modified in the same commit.  This is
        useful when you reorganize your program and move code
        around across files.  When this option is given twice,
@@ -104,9 +105,11 @@ commit.
        looks for copies from other files in any commit.
 +
 <num> is optional but it is the lower bound on the number of
-alphanumeric characters that git must detect as moving
+alphanumeric characters that git must detect as moving/copying
 between files for it to associate those lines with the parent
-commit.
+commit. And the default value is 40. If there are more than one
+`-C` options given, the <num> argument of the last `-C` will
+take effect.
 
 -h::
 --help::
index 06b2f82..ae174c9 100644 (file)
@@ -198,11 +198,11 @@ core.quotepath::
 
 core.autocrlf::
        If true, makes git convert `CRLF` at the end of lines in text files to
-       `LF` when reading from the filesystem, and convert in reverse when
-       writing to the filesystem.  The variable can be set to
+       `LF` when reading from the work tree, and convert in reverse when
+       writing to the work tree.  The variable can be set to
        'input', in which case the conversion happens only while
-       reading from the filesystem but files are written out with
-       `LF` at the end of lines.  A file is considered
+       reading from the work tree but files are written out to the work
+       tree with `LF` at the end of lines.  A file is considered
        "text" (i.e. be subjected to the autocrlf mechanism) based on
        the file's `crlf` attribute, or if `crlf` is unspecified,
        based on the file's contents.  See linkgit:gitattributes[5].
@@ -518,18 +518,12 @@ check that makes sure that existing object files will not get overwritten.
 
 core.notesRef::
        When showing commit messages, also show notes which are stored in
-       the given ref.  This ref is expected to contain files named
-       after the full SHA-1 of the commit they annotate.  The ref
-       must be fully qualified.
+       the given ref.  The ref must be fully qualified.  If the given
+       ref does not exist, it is not an error but means that no
+       notes should be printed.
 +
-If such a file exists in the given ref, the referenced blob is read, and
-appended to the commit message, separated by a "Notes (<refname>):"
-line (shortened to "Notes:" in the case of "refs/notes/commits").  If the
-given ref itself does not exist, it is not an error, but means that no
-notes should be printed.
-+
-This setting defaults to "refs/notes/commits", and can be overridden by
-the `GIT_NOTES_REF` environment variable.
+This setting defaults to "refs/notes/commits", and it can be overridden by
+the 'GIT_NOTES_REF' environment variable.  See linkgit:git-notes[1].
 
 core.sparseCheckout::
        Enable "sparse checkout" feature. See section "Sparse checkout" in
@@ -914,7 +908,7 @@ format.signoff::
 gc.aggressiveWindow::
        The window size parameter used in the delta compression
        algorithm used by 'git gc --aggressive'.  This defaults
-       to 10.
+       to 250.
 
 gc.auto::
        When there are approximately more than this many loose
@@ -1359,10 +1353,6 @@ notes.rewrite.<command>::
        automatically copies your notes from the original to the
        rewritten commit.  Defaults to `true`, but see
        "notes.rewriteRef" below.
-+
-This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
-environment variable, which must be a colon separated list of refs or
-globs.
 
 notes.rewriteMode::
        When copying notes during a rewrite (see the
@@ -1382,6 +1372,10 @@ notes.rewriteRef::
 +
 Does not have a default value; you must configure this variable to
 enable note rewriting.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
+environment variable, which must be a colon separated list of refs or
+globs.
 
 pack.window::
        The size of the window used by linkgit:git-pack-objects[1] when no
@@ -1516,7 +1510,7 @@ receive.denyDeletes::
        the ref. Use this to prevent such a ref deletion via a push.
 
 receive.denyCurrentBranch::
-       If set to true or "refuse", receive-pack will deny a ref update
+       If set to true or "refuse", git-receive-pack will deny a ref update
        to the currently checked out branch of a non-bare repository.
        Such a push is potentially dangerous because it brings the HEAD
        out of sync with the index and working tree. If set to "warn",
@@ -1642,6 +1636,7 @@ sendemail.smtppass::
 sendemail.suppresscc::
 sendemail.suppressfrom::
 sendemail.to::
+sendemail.smtpdomain::
 sendemail.smtpserver::
 sendemail.smtpserverport::
 sendemail.smtpuser::
@@ -1681,6 +1676,13 @@ If this variable is not specified, it defaults to 'normal'.
 This variable can be overridden with the -u|--untracked-files option
 of linkgit:git-status[1] and linkgit:git-commit[1].
 
+status.submodulesummary::
+       Defaults to false.
+       If this is set to a non zero number or true (identical to -1 or an
+       unlimited number), the submodule summary will be enabled and a
+       summary of commits for modified submodules will be shown (see
+       --summary-limit option of linkgit:git-submodule[1]).
+
 tar.umask::
        This variable can be used to restrict the permission bits of
        tar archive entries.  The default is 0002, which turns off the
index 60e922e..3070ddd 100644 (file)
@@ -94,8 +94,8 @@ Also, when `--raw` or `--numstat` has been given, do not munge
 pathnames and use NULs as output field terminators.
 endif::git-log[]
 ifndef::git-log[]
-       When `--raw` or `--numstat` has been given, do not munge
-       pathnames and use NULs as output field terminators.
+       When `--raw`, `--numstat`, `--name-only` or `--name-status` has been
+       given, do not munge pathnames and use NULs as output field terminators.
 endif::git-log[]
 +
 Without this option, each pathname output will have TAB, LF, double quotes,
@@ -177,7 +177,14 @@ endif::git-format-patch[]
        Break complete rewrite changes into pairs of delete and create.
 
 -M::
+ifndef::git-log[]
        Detect renames.
+endif::git-log[]
+ifdef::git-log[]
+       If generating diffs, detect and report renames for each commit.
+       For following files across renames while traversing history, see
+       `--follow`.
+endif::git-log[]
 
 -C::
        Detect copies as well as renames.  See also `--find-copies-harder`.
index 9310b65..e0ba8cc 100644 (file)
@@ -1,13 +1,8 @@
 Everyday GIT With 20 Commands Or So
 ===================================
 
-<<Basic Repository>> commands are needed by people who have a
-repository --- that is everybody, because every working tree of
-git is a repository.
-
-In addition, <<Individual Developer (Standalone)>> commands are
-essential for anybody who makes a commit, even for somebody who
-works alone.
+<<Individual Developer (Standalone)>> commands are essential for
+anybody who makes a commit, even for somebody who works alone.
 
 If you work with other people, you will need commands listed in
 the <<Individual Developer (Participant)>> section as well.
@@ -20,46 +15,6 @@ administrators who are responsible for the care and feeding
 of git repositories.
 
 
-Basic Repository[[Basic Repository]]
-------------------------------------
-
-Everybody uses these commands to maintain git repositories.
-
-  * linkgit:git-init[1] or linkgit:git-clone[1] to create a
-    new repository.
-
-  * linkgit:git-fsck[1] to check the repository for errors.
-
-  * linkgit:git-gc[1] to do common housekeeping tasks such as
-    repack and prune.
-
-Examples
-~~~~~~~~
-
-Check health and remove cruft.::
-+
-------------
-$ git fsck <1>
-$ git count-objects <2>
-$ git gc <3>
-------------
-+
-<1> running without `\--full` is usually cheap and assures the
-repository health reasonably well.
-<2> check how many loose objects there are and how much
-disk space is wasted by not repacking.
-<3> repacks the local repository and performs other housekeeping tasks.
-
-Repack a small project into single pack.::
-+
-------------
-$ git gc <1>
-------------
-+
-<1> pack all the objects reachable from the refs into one pack,
-then remove the other packs.
-
-
 Individual Developer (Standalone)[[Individual Developer (Standalone)]]
 ----------------------------------------------------------------------
 
@@ -67,6 +22,8 @@ A standalone individual developer does not exchange patches with
 other people, and works alone in a single repository, using the
 following commands.
 
+  * linkgit:git-init[1] to create a new repository.
+
   * linkgit:git-show-branch[1] to see where you are.
 
   * linkgit:git-log[1] to see what happened.
index 51cbeb7..74741a4 100644 (file)
@@ -266,9 +266,9 @@ patch::
 
        y - stage this hunk
        n - do not stage this hunk
-       q - quit, do not stage this hunk nor any of the remaining ones
-       a - stage this and all the remaining hunks in the file
-       d - do not stage this hunk nor any of the remaining hunks in the file
+       q - quit; do not stage this hunk nor any of the remaining ones
+       a - stage this hunk and all later hunks in the file
+       d - do not stage this hunk nor any of the later hunks in the file
        g - select a hunk to go to
        / - search for a hunk matching the given regex
        j - leave this hunk undecided, see next undecided hunk
index 903a690..1940256 100644 (file)
@@ -63,7 +63,9 @@ way to clean up all obsolete remote-tracking branches.
 OPTIONS
 -------
 -d::
-       Delete a branch. The branch must be fully merged in HEAD.
+       Delete a branch. The branch must be fully merged in its
+       upstream branch, or in `HEAD` if no upstream was set with
+       `--track` or `--set-upstream`.
 
 -D::
        Delete a branch irrespective of its merged status.
@@ -72,6 +74,8 @@ OPTIONS
        Create the branch's reflog.  This activates recording of
        all changes made to the branch ref, enabling use of date
        based sha1 expressions such as "<branchname>@\{yesterday}".
+       Note that in non-bare repositories, reflogs are usually
+       enabled by default by the `core.logallrefupdates` config option.
 
 -f::
 --force::
index 37c1810..a3a87fa 100644 (file)
@@ -136,6 +136,10 @@ edits from your current working tree.
 As a special case, the `"@\{-N\}"` syntax for the N-th last branch
 checks out the branch (instead of detaching).  You may also specify
 `-` which is synonymous with `"@\{-1\}"`.
++
+As a further special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
 
 <new_branch>::
        Name for the new branch.
index 78f4714..d71607a 100644 (file)
@@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit
 
 SYNOPSIS
 --------
-'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] <commit>
+'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>
 
 DESCRIPTION
 -----------
@@ -70,6 +70,10 @@ effect to your index in a row.
 --signoff::
        Add Signed-off-by line at the end of the commit message.
 
+--ff::
+       If the current HEAD is the same as the parent of the
+       cherry-pick'ed commit, then a fast forward to this commit will
+       be performed.
 
 Author
 ------
index 64fb458..69eb86e 100644 (file)
@@ -95,10 +95,11 @@ OPTIONS
        read the message from the standard input.
 
 --author=<author>::
-       Override the author name used in the commit.  You can use the
-       standard `A U Thor <author@example.com>` format.  Otherwise,
-       an existing commit that matches the given string and its author
-       name is used.
+       Override the commit author. Specify an explicit author using the
+       standard `A U Thor <author@example.com>` format. Otherwise <author>
+       is assumed to be a pattern and is used to search for an existing
+       commit by that author (i.e. rev-list --all -i --author=<author>);
+       the commit author is then copied from the first such commit found.
 
 --date=<date>::
        Override the author date used in the commit.
index 948ea26..400fe7f 100644 (file)
@@ -8,13 +8,13 @@ git-fetch - Download objects and refs from another repository
 
 SYNOPSIS
 --------
-'git fetch' <options> <repository> <refspec>...
+'git fetch' [<options>] [<repository> [<refspec>...]]
 
-'git fetch' <options> <group>
+'git fetch' [<options>] <group>
 
-'git fetch' --multiple <options> [<repository> | <group>]...
+'git fetch' --multiple [<options>] [<repository> | <group>]...
 
-'git fetch' --all <options>
+'git fetch' --all [<options>]
 
 
 DESCRIPTION
index 5238820..277d9e1 100644 (file)
@@ -35,7 +35,7 @@ These services can be enabled/disabled using the per-repository
 configuration file:
 
 http.getanyfile::
-       This serves older Git clients which are unable to use the
+       This serves Git clients older than version 1.6.6 that are unable to use the
        upload pack service.  When enabled, clients are able to read
        any file within the repository, including objects that are
        no longer reachable from a branch but are still present.
index 6cafbe2..57aba42 100644 (file)
@@ -16,7 +16,9 @@ DESCRIPTION
 This command uploads a mailbox generated with 'git format-patch'
 into an IMAP drafts folder.  This allows patches to be sent as
 other email is when using mail clients that cannot read mailbox
-files directly.
+files directly. The command also works with any general mailbox
+in which emails have the fields "From", "Date", and "Subject" in
+that order.
 
 Typical usage is something like:
 
@@ -122,12 +124,6 @@ Thunderbird in particular is known to be problematic.  Thunderbird
 users may wish to visit this web page for more information:
   http://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
 
-
-BUGS
-----
-Doesn't handle lines starting with "From " in the message body.
-
-
 Author
 ------
 Derived from isync 1.0.1 by Mike McCormack.
index fb184ba..d7f6a9c 100644 (file)
@@ -132,6 +132,48 @@ Discussion
 
 include::i18n.txt[]
 
+Configuration
+-------------
+
+See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
+for settings related to diff generation.
+
+format.pretty::
+       Default for the `--format` option.  (See "PRETTY FORMATS" above.)
+       Defaults to "medium".
+
+i18n.logOutputEncoding::
+       Encoding to use when displaying logs.  (See "Discussion", above.)
+       Defaults to the value of `i18n.commitEncoding` if set, UTF-8
+       otherwise.
+
+log.date::
+       Default format for human-readable dates.  (Compare the
+       `--date` option.)  Defaults to "default", which means to write
+       dates like `Sat May 8 19:35:34 2010 -0500`.
+
+log.showroot::
+       If `false`, 'git log' and related commands will not treat the
+       initial commit as a big creation event.  Any root commits in
+       `git log -p` output would be shown without a diff attached.
+       The default is `true`.
+
+mailmap.file::
+       See linkgit:git-shortlog[1].
+
+notes.displayRef::
+       Which refs, in addition to the default set by `core.notesRef`
+       or 'GIT_NOTES_REF', to read notes from when showing commit
+       messages with the 'log' family of commands.  See
+       linkgit:git-notes[1].
++
+May be an unabbreviated ref name or a glob and may be specified
+multiple times.  A warning will be issued for refs that do not exist,
+but a glob that does not match any refs is silently ignored.
++
+This setting can be disabled by the `--no-standard-notes` option,
+overridden by the 'GIT_NOTES_DISPLAY_REF' environment variable,
+and supplemented by the `--show-notes` option.
 
 Author
 ------
index e3d58cb..3ea5aad 100644 (file)
@@ -40,16 +40,16 @@ OPTIONS
 -u::
        The commit log message, author name and author email are
        taken from the e-mail, and after minimally decoding MIME
-       transfer encoding, re-coded in UTF-8 by transliterating
+       transfer encoding, re-coded in the charset specified by
+       i18n.commitencoding (defaulting to UTF-8) by transliterating
        them.  This used to be optional but now it is the default.
 +
 Note that the patch is always used as-is without charset
 conversion, even with this flag.
 
 --encoding=<encoding>::
-       Similar to -u but if the local convention is different
-       from what is specified by i18n.commitencoding, this flag
-       can be used to override it.
+       Similar to -u.  But when re-coding, the charset specified here is
+       used instead of the one specified by i18n.commitencoding or UTF-8.
 
 -n::
        Disable all charset re-coding of the metadata.
index 9c9618c..c2325ef 100644 (file)
@@ -9,7 +9,8 @@ git-merge - Join two or more development histories together
 SYNOPSIS
 --------
 [verse]
-'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
+'git merge' [-n] [--stat] [--no-commit] [--squash]
+       [-s <strategy>] [-X <strategy-option>]
        [--[no-]rerere-autoupdate] [-m <msg>] <commit>...
 'git merge' <msg> HEAD <commit>...
 
index 4e5113b..de63ef0 100644 (file)
@@ -3,7 +3,7 @@ git-notes(1)
 
 NAME
 ----
-git-notes - Add/inspect object notes
+git-notes - Add or inspect object notes
 
 SYNOPSIS
 --------
@@ -20,24 +20,26 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This command allows you to add/remove notes to/from objects, without
-changing the objects themselves.
+Adds, removes, or reads notes attached to objects, without touching
+the objects themselves.
 
-A typical use of notes is to extend a commit message without having
-to change the commit itself. Such commit notes can be shown by `git log`
-along with the original commit message. To discern these notes from the
+By default, notes are saved to and read from `refs/notes/commits`, but
+this default can be overridden.  See the OPTIONS, CONFIGURATION, and
+ENVIRONMENT sections below.  If this ref does not exist, it will be
+quietly created when it is first needed to store a note.
+
+A typical use of notes is to supplement a commit message without
+changing the commit itself. Notes can be shown by 'git log' along with
+the original commit message. To distinguish these notes from the
 message stored in the commit object, the notes are indented like the
 message, after an unindented line saying "Notes (<refname>):" (or
-"Notes:" for the default setting).
+"Notes:" for `refs/notes/commits`).
 
-This command always manipulates the notes specified in "core.notesRef"
-(see linkgit:git-config[1]), which can be overridden by GIT_NOTES_REF.
-To change which notes are shown by 'git-log', see the
-"notes.displayRef" configuration.
+To change which notes are shown by 'git log', see the
+"notes.displayRef" configuration in linkgit:git-log[1].
 
-See the description of "notes.rewrite.<command>" in
-linkgit:git-config[1] for a way of carrying your notes across commands
-that rewrite commits.
+See the "notes.rewrite.<command>" configuration for a way to carry
+notes across commands that rewrite commits.
 
 
 SUBCOMMANDS
@@ -101,15 +103,20 @@ OPTIONS
        Use the given note message (instead of prompting).
        If multiple `-m` options are given, their values
        are concatenated as separate paragraphs.
+       Lines starting with `#` and empty lines other than a
+       single line between paragraphs will be stripped out.
 
 -F <file>::
 --file=<file>::
        Take the note message from the given file.  Use '-' to
        read the note message from the standard input.
+       Lines starting with `#` and empty lines other than a
+       single line between paragraphs will be stripped out.
 
 -C <object>::
 --reuse-message=<object>::
-       Reuse the note message from the given note object.
+       Take the note message from the given blob object (for
+       example, another note).
 
 -c <object>::
 --reedit-message=<object>::
@@ -117,22 +124,144 @@ OPTIONS
        the user can further edit the note message.
 
 --ref <ref>::
-       Manipulate the notes tree in <ref>.  This overrides both
-       GIT_NOTES_REF and the "core.notesRef" configuration.  The ref
+       Manipulate the notes tree in <ref>.  This overrides
+       'GIT_NOTES_REF' and the "core.notesRef" configuration.  The ref
        is taken to be in `refs/notes/` if it is not qualified.
 
 
-NOTES
------
+DISCUSSION
+----------
+
+Commit notes are blobs containing extra information about an object
+(usually information to supplement a commit's message).  These blobs
+are taken from notes refs.  A notes ref is usually a branch which
+contains "files" whose paths are the object names for the objects
+they describe, with some directory separators included for performance
+reasons footnote:[Permitted pathnames have the form
+'ab'`/`'cd'`/`'ef'`/`'...'`/`'abcdef...': a sequence of directory
+names of two hexadecimal digits each followed by a filename with the
+rest of the object ID.].
 
 Every notes change creates a new commit at the specified notes ref.
 You can therefore inspect the history of the notes by invoking, e.g.,
-`git log -p notes/commits`.
+`git log -p notes/commits`.  Currently the commit message only records
+which operation triggered the update, and the commit authorship is
+determined according to the usual rules (see linkgit:git-commit[1]).
+These details may change in the future.
+
+It is also permitted for a notes ref to point directly to a tree
+object, in which case the history of the notes can be read with
+`git log -p -g <refname>`.
+
+
+EXAMPLES
+--------
+
+You can use notes to add annotations with information that was not
+available at the time a commit was written.
+
+------------
+$ git notes add -m 'Tested-by: Johannes Sixt <j6t@kdbg.org>' 72a144e2
+$ git show -s 72a144e
+[...]
+    Signed-off-by: Junio C Hamano <gitster@pobox.com>
+
+Notes:
+    Tested-by: Johannes Sixt <j6t@kdbg.org>
+------------
+
+In principle, a note is a regular Git blob, and any kind of
+(non-)format is accepted.  You can binary-safely create notes from
+arbitrary files using 'git hash-object':
+
+------------
+$ cc *.c
+$ blob=$(git hash-object -w a.out)
+$ git notes --ref=built add -C "$blob" HEAD
+------------
+
+Of course, it doesn't make much sense to display non-text-format notes
+with 'git log', so if you use such notes, you'll probably need to write
+some special-purpose tools to do something useful with them.
+
+
+CONFIGURATION
+-------------
+
+core.notesRef::
+       Notes ref to read and manipulate instead of
+       `refs/notes/commits`.  Must be an unabbreviated ref name.
+       This setting can be overridden through the environment and
+       command line.
 
-Currently the commit message only records which operation triggered
-the update, and the commit authorship is determined according to the
-usual rules (see linkgit:git-commit[1]).  These details may change in
-the future.
+notes.displayRef::
+       Which ref (or refs, if a glob or specified more than once), in
+       addition to the default set by `core.notesRef` or
+       'GIT_NOTES_REF', to read notes from when showing commit
+       messages with the 'git log' family of commands.
+       This setting can be overridden on the command line or by the
+       'GIT_NOTES_DISPLAY_REF' environment variable.
+       See linkgit:git-log[1].
+
+notes.rewrite.<command>::
+       When rewriting commits with <command> (currently `amend` or
+       `rebase`), if this variable is `false`, git will not copy
+       notes from the original to the rewritten commit.  Defaults to
+       `true`.  See also "`notes.rewriteRef`" below.
++
+This setting can be overridden by the 'GIT_NOTES_REWRITE_REF'
+environment variable.
+
+notes.rewriteMode::
+       When copying notes during a rewrite, what to do if the target
+       commit already has a note.  Must be one of `overwrite`,
+       `concatenate`, and `ignore`.  Defaults to `concatenate`.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
+environment variable.
+
+notes.rewriteRef::
+       When copying notes during a rewrite, specifies the (fully
+       qualified) ref whose notes should be copied.  May be a glob,
+       in which case notes in all matching refs will be copied.  You
+       may also specify this configuration several times.
++
+Does not have a default value; you must configure this variable to
+enable note rewriting.
++
+Can be overridden with the 'GIT_NOTES_REWRITE_REF' environment variable.
+
+
+ENVIRONMENT
+-----------
+
+'GIT_NOTES_REF'::
+       Which ref to manipulate notes from, instead of `refs/notes/commits`.
+       This overrides the `core.notesRef` setting.
+
+'GIT_NOTES_DISPLAY_REF'::
+       Colon-delimited list of refs or globs indicating which refs,
+       in addition to the default from `core.notesRef` or
+       'GIT_NOTES_REF', to read notes from when showing commit
+       messages.
+       This overrides the `notes.displayRef` setting.
++
+A warning will be issued for refs that do not exist, but a glob that
+does not match any refs is silently ignored.
+
+'GIT_NOTES_REWRITE_MODE'::
+       When copying notes during a rewrite, what to do if the target
+       commit already has a note.
+       Must be one of `overwrite`, `concatenate`, and `ignore`.
+       This overrides the `core.rewriteMode` setting.
+
+'GIT_NOTES_REWRITE_REF'::
+       When rewriting commits, which notes to copy from the original
+       to the rewritten commit.  Must be a colon-delimited list of
+       refs or globs.
++
+If not set in the environment, the list of notes to copy depends
+on the `notes.rewrite.<command>` and `notes.rewriteRef` settings.
 
 
 Author
index 59dc8b1..4857024 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
           [--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream]
-          [<repository> <refspec>...]
+          [<repository> [<refspec>...]]
 
 DESCRIPTION
 -----------
index 823f2a4..50ba2e4 100644 (file)
@@ -206,6 +206,10 @@ OPTIONS
        --onto option is not specified, the starting point is
        <upstream>.  May be any valid commit, and not just an
        existing branch name.
++
+As a special case, you may use "A...B" as a shortcut for the
+merge base of A and B if there is exactly one merge base. You can
+leave out at most one of A and B, in which case it defaults to HEAD.
 
 <upstream>::
        Upstream branch to compare against.  May be any valid commit,
@@ -274,9 +278,16 @@ which makes little sense.
 -f::
 --force-rebase::
        Force the rebase even if the current branch is a descendant
-       of the commit you are rebasing onto.  Normally the command will
+       of the commit you are rebasing onto.  Normally non-interactive rebase will
        exit with the message "Current branch is up to date" in such a
        situation.
+       Incompatible with the --interactive option.
++
+You may find this (or --no-ff with an interactive rebase) helpful after
+reverting a topic branch merge, as this option recreates the topic branch with
+fresh commits so it can be remerged successfully without needing to "revert
+the reversion" (see the
+link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
 
 --ignore-whitespace::
 --whitespace=<option>::
@@ -288,6 +299,7 @@ which makes little sense.
 --ignore-date::
        These flags are passed to 'git am' to easily change the dates
        of the rebased commits (see linkgit:git-am[1]).
+       Incompatible with the --interactive option.
 
 -i::
 --interactive::
@@ -316,7 +328,19 @@ which makes little sense.
        commit to be modified, and change the action of the moved
        commit from `pick` to `squash` (or `fixup`).
 +
-This option is only valid when '--interactive' option is used.
+This option is only valid when the '--interactive' option is used.
+
+--no-ff::
+       With --interactive, cherry-pick all rebased commits instead of
+       fast-forwarding over the unchanged ones.  This ensures that the
+       entire history of the rebased branch is composed of new commits.
++
+Without --interactive, this is a synonym for --force-rebase.
++
+You may find this helpful after reverting a topic branch merge, as this option
+recreates the topic branch with fresh commits so it can be remerged
+successfully without needing to "revert the reversion" (see the
+link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
 
 include::merge-strategies.txt[]
 
index 1b5f61a..3a23477 100644 (file)
@@ -3,20 +3,69 @@ git-remote-helpers(1)
 
 NAME
 ----
-git-remote-helpers - Helper programs for interoperation with remote git
+git-remote-helpers - Helper programs to interact with remote repositories
 
 SYNOPSIS
 --------
-'git remote-<transport>' <remote>
+'git remote-<transport>' <repository> [<URL>]
 
 DESCRIPTION
 -----------
 
-These programs are normally not used directly by end users, but are
-invoked by various git programs that interact with remote repositories
-when the repository they would operate on will be accessed using
-transport code not linked into the main git binary. Various particular
-helper programs will behave as documented here.
+Remote helper programs are normally not used directly by end users,
+but they are invoked by git when it needs to interact with remote
+repositories git does not support natively.  A given helper will
+implement a subset of the capabilities documented here. When git
+needs to interact with a repository using a remote helper, it spawns
+the helper as an independent process, sends commands to the helper's
+standard input, and expects results from the helper's standard
+output. Because a remote helper runs as an independent process from
+git, there is no need to re-link git to add a new helper, nor any
+need to link the helper with the implementation of git.
+
+Every helper must support the "capabilities" command, which git will
+use to determine what other commands the helper will accept.  Other
+commands generally concern facilities like discovering and updating
+remote refs, transporting objects between the object database and
+the remote repository, and updating the local object store.
+
+Helpers supporting the 'fetch' capability can discover refs from the
+remote repository and transfer objects reachable from those refs to
+the local object store. Helpers supporting the 'push' capability can
+transfer local objects to the remote repository and update remote refs.
+
+Git comes with a "curl" family of remote helpers, that handle various
+transport protocols, such as 'git-remote-http', 'git-remote-https',
+'git-remote-ftp' and 'git-remote-ftps'. They implement the capabilities
+'fetch', 'option', and 'push'.
+
+INVOCATION
+----------
+
+Remote helper programs are invoked with one or (optionally) two
+arguments. The first argument specifies a remote repository as in git;
+it is either the name of a configured remote or a URL. The second
+argument specifies a URL; it is usually of the form
+'<transport>://<address>', but any arbitrary string is possible.
+
+When git encounters a URL of the form '<transport>://<address>', where
+'<transport>' is a protocol that it cannot handle natively, it
+automatically invokes 'git remote-<transport>' with the full URL as
+the second argument. If such a URL is encountered directly on the
+command line, the first argument is the same as the second, and if it
+is encountered in a configured remote, the first argument is the name
+of that remote.
+
+A URL of the form '<transport>::<address>' explicitly instructs git to
+invoke 'git remote-<transport>' with '<address>' as the second
+argument. If such a URL is encountered directly on the command line,
+the first argument is '<address>', and if it is encountered in a
+configured remote, the first argument is the name of that remote.
+
+Additionally, when a configured remote has 'remote.<name>.vcs' set to
+'<transport>', git explicitly invokes 'git remote-<transport>' with
+'<name>' as the first argument. If set, the second argument is
+'remote.<name>.url'; otherwise, the second argument is omitted.
 
 COMMANDS
 --------
@@ -25,8 +74,8 @@ Commands are given by the caller on the helper's standard input, one per line.
 
 'capabilities'::
        Lists the capabilities of the helper, one per line, ending
-       with a blank line. Each capability may be preceded with '*'.
-       This marks them mandatory for git version using the remote
+       with a blank line. Each capability may be preceded with '*',
+       which marks them mandatory for git version using the remote
        helper to understand (unknown mandatory capability is fatal
        error).
 
@@ -35,27 +84,27 @@ Commands are given by the caller on the helper's standard input, one per line.
        [<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
        a symref, or "?" to indicate that the helper could not get the
        value of the ref. A space-separated list of attributes follows
-       the name; unrecognized attributes are ignored. After the
-       complete list, outputs a blank line.
+       the name; unrecognized attributes are ignored. The list ends
+       with a blank line.
 +
 If 'push' is supported this may be called as 'list for-push'
 to obtain the current refs prior to sending one or more 'push'
 commands to the helper.
 
 'option' <name> <value>::
-       Set the transport helper option <name> to <value>.  Outputs a
+       Sets the transport helper option <name> to <value>.  Outputs a
        single line containing one of 'ok' (option successfully set),
        'unsupported' (option not recognized) or 'error <msg>'
-       (option <name> is supported but <value> is not correct
+       (option <name> is supported but <value> is not valid
        for it).  Options should be set before other commands,
-       and may how those commands behave.
+       and may influence the behavior of those commands.
 +
 Supported if the helper has the "option" capability.
 
 'fetch' <sha1> <name>::
        Fetches the given object, writing the necessary objects
        to the database.  Fetch commands are sent in a batch, one
-       per line, and the batch is terminated with a blank line.
+       per line, terminated with a blank line.
        Outputs a single blank line when all fetch commands in the
        same batch are complete. Only objects which were reported
        in the ref list with a sha1 may be fetched this way.
@@ -67,7 +116,7 @@ suitably updated.
 Supported if the helper has the "fetch" capability.
 
 'push' +<src>:<dst>::
-       Pushes the given <src> commit or branch locally to the
+       Pushes the given local <src> commit or branch to the
        remote branch described by <dst>.  A batch sequence of
        one or more push commands is terminated with a blank line.
 +
@@ -91,6 +140,9 @@ Supported if the helper has the "push" capability.
        by applying the refspecs from the "refspec" capability to the
        name of the ref.
 +
+Especially useful for interoperability with a foreign versioning
+system.
++
 Supported if the helper has the "import" capability.
 
 'connect' <service>::
@@ -119,16 +171,11 @@ CAPABILITIES
 ------------
 
 'fetch'::
-       This helper supports the 'fetch' command.
-
 'option'::
-       This helper supports the option command.
-
 'push'::
-       This helper supports the 'push' command.
-
 'import'::
-       This helper supports the 'import' command.
+'connect'::
+       This helper supports the corresponding command with the same name.
 
 'refspec' 'spec'::
        When using the import command, expect the source ref to have
@@ -140,9 +187,6 @@ CAPABILITIES
        all, it must cover all refs reported by the list command; if
        it is not used, it is effectively "*:*"
 
-'connect'::
-       This helper supports the 'connect' command.
-
 REF LIST ATTRIBUTES
 -------------------
 
@@ -158,19 +202,19 @@ REF LIST ATTRIBUTES
 OPTIONS
 -------
 'option verbosity' <N>::
-       Change the level of messages displayed by the helper.
-       When N is 0 the end-user has asked the process to be
-       quiet, and the helper should produce only error output.
-       N of 1 is the default level of verbosity, higher values
+       Changes the verbosity of messages displayed by the helper.
+       A value of 0 for N means that processes operate
+       quietly, and the helper produces only error output.
+       1 is the default level of verbosity, and higher values
        of N correspond to the number of -v flags passed on the
        command line.
 
 'option progress' \{'true'|'false'\}::
-       Enable (or disable) progress messages displayed by the
+       Enables (or disables) progress messages displayed by the
        transport helper during a command.
 
 'option depth' <depth>::
-       Deepen the history of a shallow repository.
+       Deepens the history of a shallow repository.
 
 'option followtags' \{'true'|'false'\}::
        If enabled the helper should automatically fetch annotated
@@ -186,11 +230,15 @@ OPTIONS
        helpers this only applies to the 'push', if supported.
 
 'option servpath <c-style-quoted-path>'::
-       Set service path (--upload-pack, --receive-pack etc.) for
-       next connect. Remote helper MAY support this option. Remote
-       helper MUST NOT rely on this option being set before
+       Sets service path (--upload-pack, --receive-pack etc.) for
+       next connect. Remote helper may support this option, but
+       must not rely on this option being set before
        connect request occurs.
 
+SEE ALSO
+--------
+linkgit:git-remote[1]
+
 Documentation
 -------------
 Documentation by Daniel Barkalow and Ilari Liusvaara
index ced35b2..12622fc 100644 (file)
@@ -119,6 +119,13 @@ Sending
        value reverts to plain SMTP.  Default is the value of
        'sendemail.smtpencryption'.
 
+--smtp-domain=<FQDN>::
+       Specifies the Fully Qualified Domain Name (FQDN) used in the
+       HELO/EHLO command to the SMTP server.  Some servers require the
+       FQDN to match your IP address.  If not set, git send-email attempts
+       to determine your FQDN automatically.  Default is the value of
+       'sendemail.smtpdomain'.
+
 --smtp-pass[=<password>]::
        Password for SMTP-AUTH. The argument is optional: If no
        argument is specified, then the empty string is used as
@@ -300,6 +307,21 @@ sendemail.confirm::
        in the previous section for the meaning of these values.
 
 
+Use gmail as the smtp server
+----------------------------
+
+Add the following section to the config file:
+
+       [sendemail]
+               smtpencryption = tls
+               smtpserver = smtp.gmail.com
+               smtpuser = yourname@gmail.com
+               smtpserverport = 587
+
+Note: the following perl modules are required
+      Net::SMTP::SSL, MIME::Base64 and Authen::SASL
+
+
 Author
 ------
 Written by Ryan Anderson <ryan@michonline.com>
index dfd4d0c..bc1ac77 100644 (file)
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]
-'git shortlog' [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...]
+'git shortlog' [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] <commit>...
 
 DESCRIPTION
 -----------
@@ -19,6 +19,11 @@ the first line of the commit message will be shown.
 
 Additionally, "[PATCH]" will be stripped from the commit description.
 
+If no revisions are passed on the command line and either standard input
+is not a terminal or there is no current branch, 'git shortlog' will
+output a summary of the log read from standard input, without
+reference to the current repository.
+
 OPTIONS
 -------
 
@@ -39,6 +44,14 @@ OPTIONS
 --email::
        Show the email address of each author.
 
+--format[='<format>']::
+       Instead of the commit subject, use some other information to
+       describe each commit.  '<format>' can be any string accepted
+       by the `--format` option of 'git log', such as '{asterisk} [%h] %s'.
+       (See the "PRETTY FORMATS" section of linkgit:git-log[1].)
+
+       Each pretty-printed commit will be rewrapped before it is shown.
+
 -w[<width>[,<indent1>[,<indent2>]]]::
        Linewrap the output by wrapping each line at `width`.  The first
        line of each entry is indented by `indent1` spaces, and the second
index df17d49..3f9d9c6 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git show-ref' [-q|--quiet] [--verify] [--head] [-d|--dereference]
             [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags]
-            [--heads] [--] <pattern>...
+            [--heads] [--] [<pattern>...]
 'git show-ref' --exclude-existing[=<pattern>] < ref-list
 
 DESCRIPTION
index 1cab91b..2d4bbfc 100644 (file)
@@ -72,21 +72,37 @@ In short-format, the status of each path is shown as
 
 where `PATH1` is the path in the `HEAD`, and ` -> PATH2` part is
 shown only when `PATH1` corresponds to a different path in the
-index/worktree (i.e. renamed).
-
-For unmerged entries, `X` shows the status of stage #2 (i.e. ours) and `Y`
-shows the status of stage #3 (i.e. theirs).
-
-For entries that do not have conflicts, `X` shows the status of the index,
-and `Y` shows the status of the work tree.  For untracked paths, `XY` are
-`??`.
+index/worktree (i.e. the file is renamed). The 'XY' is a two-letter
+status code.
+
+The fields (including the `->`) are separated from each other by a
+single space. If a filename contains whitespace or other nonprintable
+characters, that field will be quoted in the manner of a C string
+literal: surrounded by ASCII double quote (34) characters, and with
+interior special characters backslash-escaped.
+
+For paths with merge conflicts, `X` and 'Y' show the modification
+states of each side of the merge. For paths that do not have merge
+conflicts, `X` shows the status of the index, and `Y` shows the status
+of the work tree.  For untracked paths, `XY` are `??`.  Other status
+codes can be interpreted as follows:
+
+* ' ' = unmodified
+* 'M' = modified
+* 'A' = added
+* 'D' = deleted
+* 'R' = renamed
+* 'C' = copied
+* 'U' = updated but unmerged
+
+Ignored files are not listed.
 
     X          Y     Meaning
     -------------------------------------------------
               [MD]   not updated
     M        [ MD]   updated in index
     A        [ MD]   added to index
-    D        [ MD]   deleted from index
+    D         [ M]   deleted from index
     R        [ MD]   renamed in index
     C        [ MD]   copied in index
     [MARC]           index and work tree matches
@@ -104,6 +120,15 @@ and `Y` shows the status of the work tree.  For untracked paths, `XY` are
     ?           ?    untracked
     -------------------------------------------------
 
+There is an alternate -z format recommended for machine parsing.  In
+that format, the status field is the same, but some other things
+change.  First, the '->' is omitted from rename entries and the field
+order is reversed (e.g 'from -> to' becomes 'to from'). Second, a NUL
+(ASCII 0) follows each filename, replacing space as a field separator
+and the terminating newline (but a space still separates the status
+field from the first filename).  Third, filenames containing special
+characters are not specially formatted; no quoting or
+backslash-escaping is performed.
 
 CONFIGURATION
 -------------
index 68dc187..765d4b3 100644 (file)
@@ -93,8 +93,6 @@ OPTIONS
 This option can be also used as a coarse file-level mechanism
 to ignore uncommitted changes in tracked files (akin to what
 `.gitignore` does for untracked files).
-You should remember that an explicit 'git add' operation will
-still cause the file to be refreshed from the working tree.
 Git will fail (gracefully) in case it needs to modify this file
 in the index e.g. when merging in a commit;
 thus, in case the assumed-untracked file is changed upstream,
index 4e00b31..c4024d0 100644 (file)
@@ -43,9 +43,17 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.7.0.3/git.html[documentation for release 1.7.0.3]
+* link:v1.7.1/git.html[documentation for release 1.7.1]
 
 * release notes for
+  link:RelNotes-1.7.1.txt[1.7.1].
+
+* link:v1.7.0.6/git.html[documentation for release 1.7.0.6]
+
+* release notes for
+  link:RelNotes-1.7.0.6.txt[1.7.0.6],
+  link:RelNotes-1.7.0.5.txt[1.7.0.5],
+  link:RelNotes-1.7.0.4.txt[1.7.0.4],
   link:RelNotes-1.7.0.3.txt[1.7.0.3],
   link:RelNotes-1.7.0.2.txt[1.7.0.2],
   link:RelNotes-1.7.0.1.txt[1.7.0.1],
index 9de8caf..5d91a7e 100644 (file)
@@ -227,8 +227,8 @@ changes that touch a specified string, and is controlled by the
 commands.
 
 When diffcore-pickaxe is in use, it checks if there are
-filepairs whose "original" side has the specified string and
-whose "result" side does not.  Such a filepair represents "the
+filepairs whose "result" side has the specified string and
+whose "origin" side does not.  Such a filepair represents "the
 string appeared in this changeset".  It also checks for the
 opposite case that loses the specified string.
 
index 98c459d..e10fa88 100644 (file)
@@ -83,16 +83,20 @@ Patterns have the following format:
 
  - If the pattern does not contain a slash '/', git treats it as
    a shell glob pattern and checks for a match against the
-   pathname without leading directories.
+   pathname relative to the location of the `.gitignore` file
+   (relative to the toplevel of the work tree if not from a
+   `.gitignore` file).
 
  - Otherwise, git treats the pattern as a shell glob suitable
    for consumption by fnmatch(3) with the FNM_PATHNAME flag:
    wildcards in the pattern will not match a / in the pathname.
    For example, "Documentation/\*.html" matches
-   "Documentation/git.html" but not
-   "Documentation/ppc/ppc.html".  A leading slash matches the
-   beginning of the pathname; for example, "/*.c" matches
-   "cat-file.c" but not "mozilla-sha1/sha1.c".
+   "Documentation/git.html" but not "Documentation/ppc/ppc.html"
+   or "tools/perf/Documentation/perf.html".
+
+ - A leading slash matches the beginning of the pathname.
+   For example, "/*.c" matches "cat-file.c" but not
+   "mozilla-sha1/sha1.c".
 
 An example:
 
index 3b4a390..ff5c0bc 100644 (file)
@@ -142,6 +142,8 @@ different resolution strategies:
    revert of a merge was rebuilt from scratch (i.e. rebasing and fixing,
    as you seem to have interpreted), then re-merging the result without
    doing anything else fancy would be the right thing to do.
+   (See the ADDENDUM below for how to rebuild a branch from scratch
+   without changing its original branching-off point.)
 
 However, there are things to keep in mind when reverting a merge (and
 reverting such a revert).
@@ -177,3 +179,91 @@ the answer is: "oops, I really shouldn't have merged it, because it wasn't
 ready yet, and I really need to undo _all_ of the merge"). So then you
 really should revert the merge, but when you want to re-do the merge, you
 now need to do it by reverting the revert.
+
+ADDENDUM
+
+Sometimes you have to rewrite one of a topic branch's commits *and* you can't
+change the topic's branching-off point.  Consider the following situation:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C
+
+where commit W reverted commit M because it turned out that commit B was wrong
+and needs to be rewritten, but you need the rewritten topic to still branch
+from commit P (perhaps P is a branching-off point for yet another branch, and
+you want be able to merge the topic into both branches).
+
+The natural thing to do in this case is to checkout the A-B-C branch and use
+"rebase -i P" to change commit B.  However this does not rewrite commit A,
+because "rebase -i" by default fast-forwards over any initial commits selected
+with the "pick" command.  So you end up with this:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C   <-- old branch
+    \
+     B'---C'   <-- naively rewritten branch
+
+To merge A-B'-C' into the mainline branch you would still have to first revert
+commit W in order to pick up the changes in A, but then it's likely that the
+changes in B' will conflict with the original B changes re-introduced by the
+reversion of W.
+
+However, you can avoid these problems if you recreate the entire branch,
+including commit A:
+
+   A'---B'---C'  <-- completely rewritten branch
+  /
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C
+
+You can merge A'-B'-C' into the mainline branch without worrying about first
+reverting W.  Mainline's history would look like this:
+
+   A'---B'---C'------------------
+  /                              \
+ P---o---o---M---x---x---W---x---M2
+  \         /
+   A---B---C
+
+But if you don't actually need to change commit A, then you need some way to
+recreate it as a new commit with the same changes in it.  The rebase commmand's
+--no-ff option provides a way to do this:
+
+    $ git rebase [-i] --no-ff P
+
+The --no-ff option creates a new branch A'-B'-C' with all-new commits (all the
+SHA IDs will be different) even if in the interactive case you only actually
+modify commit B.  You can then merge this new branch directly into the mainline
+branch and be sure you'll get all of the branch's changes.
+
+You can also use --no-ff in cases where you just add extra commits to the topic
+to fix it up.  Let's revisit the situation discussed at the start of this howto:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C----------------D---E   <-- fixed-up topic branch
+
+At this point, you can use --no-ff to recreate the topic branch:
+
+    $ git checkout E
+    $ git rebase --no-ff P
+
+yielding
+
+   A'---B'---C'------------D'---E'  <-- recreated topic branch
+  /
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C----------------D---E
+
+You can merge the recreated branch into the mainline without reverting commit W,
+and mainline's history will look like this:
+
+   A'---B'---C'------------D'---E'
+  /                              \
+ P---o---o---M---x---x---W---x---M2
+  \         /
+   A---B---C
index 37ce9a1..722d704 100644 (file)
@@ -62,6 +62,11 @@ option can be used to override --squash.
        is used instead ('git merge-recursive' when merging a single
        head, 'git merge-octopus' otherwise).
 
+-X <option>::
+--strategy-option=<option>::
+       Pass merge strategy specific option through to the merge
+       strategy.
+
 --summary::
 --no-summary::
        Synonyms to --stat and --no-stat; these are deprecated and will be
@@ -76,8 +81,3 @@ ifndef::git-pull[]
 --verbose::
        Be verbose.
 endif::git-pull[]
-
--X <option>::
---strategy-option=<option>::
-       Pass merge strategy specific option through to the merge
-       strategy.
index 1686a54..c85a52c 100644 (file)
@@ -76,9 +76,9 @@ displayed in full, regardless of whether --abbrev or
 true parent commits, without taking grafts nor history
 simplification into account.
 
-* 'format:'
+* 'format:<string>'
 +
-The 'format:' format allows you to specify which information
+The 'format:<string>' format allows you to specify which information
 you want to show. It works a little bit like printf format,
 with the notable exception that you get a newline with '%n'
 instead of '\n'.
index af6d2b9..d78e121 100644 (file)
@@ -3,8 +3,9 @@
 
        Pretty-print the contents of the commit logs in a given format,
        where '<format>' can be one of 'oneline', 'short', 'medium',
-       'full', 'fuller', 'email', 'raw' and 'format:<string>'.
-       When omitted, the format defaults to 'medium'.
+       'full', 'fuller', 'email', 'raw' and 'format:<string>'.  See
+       the "PRETTY FORMATS" section for some additional details for each
+       format.  When omitted, the format defaults to 'medium'.
 +
 Note: you can specify the default pretty format in the repository
 configuration (see linkgit:git-config[1]).
index 293bb15..6d8c24b 100644 (file)
@@ -104,8 +104,12 @@ write `string_list_insert(...)->util = ...;`.
 `unsorted_string_list_has_string`::
 
        It's like `string_list_has_string()` but for unsorted lists.
+
+`unsorted_string_list_lookup`::
+
+       It's like `string_list_lookup()` but for unsorted lists.
 +
-This function needs to look through all items, as opposed to its
+The above two functions need to look through all items, as opposed to their
 counterpart for sorted lists, which performs a binary search.
 
 Data structures
index 9a5cdaf..369f91d 100644 (file)
@@ -36,7 +36,7 @@ Git Transport
 
 The Git transport starts off by sending the command and repository
 on the wire using the pkt-line format, followed by a NUL byte and a
-hostname paramater, terminated by a NUL byte.
+hostname parameter, terminated by a NUL byte.
 
    0032git-upload-pack /project.git\0host=myserver.com\0
 
@@ -331,7 +331,7 @@ An incremental update (fetch) response might look like this:
 
    C: 0009done\n
 
-   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
    S: [PACKFILE]
 ----
 
@@ -488,7 +488,7 @@ An example client/server communication might look like this:
    C: 0000
    C: [PACKDATA]
 
-   S: 000aunpack ok\n
-   S: 0014ok refs/heads/debug\n
-   S: 0026ng refs/heads/master non-fast-forward\n
+   S: 000eunpack ok\n
+   S: 0018ok refs/heads/debug\n
+   S: 002ang refs/heads/master non-fast-forward\n
 ----
index 459a394..1dcd1e7 100644 (file)
@@ -1,44 +1,57 @@
 GIT URLS[[URLS]]
 ----------------
 
-One of the following notations can be used
-to name the remote repository:
+In general, URLs contain information about the transport protocol, the
+address of the remote server, and the path to the repository.
+Depending on the transport protocol, some of this information may be
+absent.
+
+Git natively supports ssh, git, http, https, ftp, ftps, and rsync
+protocols. The following syntaxes may be used with them:
 
-- rsync://host.xz/path/to/repo.git/
-- http://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- https://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- git://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- git://host.xz{startsb}:port{endsb}/~user/path/to/repo.git/
 - ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/
-- ssh://{startsb}user@{endsb}host.xz/path/to/repo.git/
-- ssh://{startsb}user@{endsb}host.xz/~user/path/to/repo.git/
-- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git
+- git://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- http{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- ftp{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
+- rsync://host.xz/path/to/repo.git/
 
-SSH is the default transport protocol over the network.  You can
-optionally specify which user to log-in as, and an alternate,
-scp-like syntax is also supported.  Both syntaxes support
-username expansion, as does the native git protocol, but
-only the former supports port specification. The following
-three are identical to the last three above, respectively:
+An alternative scp-like syntax may also be used with the ssh protocol:
 
-- {startsb}user@{endsb}host.xz:/path/to/repo.git/
-- {startsb}user@{endsb}host.xz:~user/path/to/repo.git/
-- {startsb}user@{endsb}host.xz:path/to/repo.git
+- {startsb}user@{endsb}host.xz:path/to/repo.git/
 
-To sync with a local directory, you can use:
+The ssh and git protocols additionally support ~username expansion:
+
+- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
+- git://host.xz{startsb}:port{endsb}/~{startsb}user{endsb}/path/to/repo.git/
+- {startsb}user@{endsb}host.xz:/~{startsb}user{endsb}/path/to/repo.git/
+
+For local respositories, also supported by git natively, the following
+syntaxes may be used:
 
 - /path/to/repo.git/
 - file:///path/to/repo.git/
 
 ifndef::git-clone[]
-They are mostly equivalent, except when cloning.  See
-linkgit:git-clone[1] for details.
+These two syntaxes are mostly equivalent, except when cloning, when
+the former implies --local option. See linkgit:git-clone[1] for
+details.
 endif::git-clone[]
 
 ifdef::git-clone[]
-They are equivalent, except the former implies --local option.
+These two syntaxes are mostly equivalent, except the former implies
+--local option.
 endif::git-clone[]
 
+When git doesn't know how to handle a certain transport protocol, it
+attempts to use the 'remote-<transport>' remote helper, if one
+exists. To explicitly request a remote helper, the following syntax
+may be used:
+
+- <transport>::<address>
+
+where <address> may be a path, a server and path, or an arbitrary
+URL-like string recognized by the specific remote helper being
+invoked. See linkgit:git-remote-helpers[1] for details.
 
 If there are a large number of similarly-named remote repositories and
 you want to use a different format for them (such that the URLs you
index 076c18e..82fd726 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.0.3
+DEF_VER=v1.7.1
 
 LF='
 '
@@ -12,7 +12,7 @@ if test -f version
 then
        VN=$(cat version) || VN="$DEF_VER"
 elif test -d .git -o -f .git &&
-       VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
+       VN=$(git describe --match "v[0-9]*" --abbrev=4 HEAD 2>/dev/null) &&
        case "$VN" in
        *$LF*) (exit 1) ;;
        v[0-9]*)
index 3a6c6ea..b18768e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -31,10 +31,13 @@ all::
 # Define EXPATDIR=/foo/bar if your expat header and library files are in
 # /foo/bar/include and /foo/bar/lib directories.
 #
+# Define HAVE_PATHS_H if you have paths.h and want to use the default PATH
+# it specifies.
+#
 # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
 #
 # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
-# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
+# d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7).
 #
 # Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
 # do not support the 'size specifiers' introduced by C99, namely ll, hh,
@@ -109,7 +112,7 @@ all::
 # Define NO_PTHREADS if you do not have or do not want to use Pthreads.
 #
 # Define NO_PREAD if you have a problem with pread() system call (e.g.
-# cygwin.dll before v1.5.22).
+# cygwin1.dll before v1.5.22).
 #
 # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
 # generally faster on your platform than accessing the working directory.
@@ -203,6 +206,9 @@ all::
 # Define JSMIN to point to JavaScript minifier that functions as
 # a filter to have gitweb.js minified.
 #
+# Define CSSMIN to point to a CSS minifier in order to generate a minified
+# version of gitweb.css
+#
 # Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
 # you want to use something different.  The value will be interpreted by the
 # shell at runtime when it is used.
@@ -279,9 +285,6 @@ lib = lib
 # DESTDIR=
 pathsep = :
 
-# JavaScript minifier invocation that can function as filter
-JSMIN =
-
 export prefix bindir sharedir sysconfdir
 
 CC = gcc
@@ -735,10 +738,12 @@ EXTLIBS =
 ifeq ($(uname_S),Linux)
        NO_STRLCPY = YesPlease
        NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
        NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
 endif
 ifeq ($(uname_S),UnixWare)
        CC = cc
@@ -831,22 +836,24 @@ ifeq ($(uname_S),SunOS)
        BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
 endif
 ifeq ($(uname_O),Cygwin)
-       NO_D_TYPE_IN_DIRENT = YesPlease
-       NO_D_INO_IN_DIRENT = YesPlease
-       NO_STRCASESTR = YesPlease
-       NO_MEMMEM = YesPlease
-       NO_MKSTEMPS = YesPlease
-       NO_SYMLINK_HEAD = YesPlease
+       ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
+               NO_D_TYPE_IN_DIRENT = YesPlease
+               NO_D_INO_IN_DIRENT = YesPlease
+               NO_STRCASESTR = YesPlease
+               NO_MEMMEM = YesPlease
+               NO_MKSTEMPS = YesPlease
+               NO_SYMLINK_HEAD = YesPlease
+               NO_IPV6 = YesPlease
+               OLD_ICONV = UnfortunatelyYes
+       endif
        NEEDS_LIBICONV = YesPlease
        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
        NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
-       OLD_ICONV = UnfortunatelyYes
        NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
        # There are conflicting reports about this.
        # On some boxes NO_MMAP is needed, and not so elsewhere.
        # Try commenting this out if you suspect MMAP is more efficient
        NO_MMAP = YesPlease
-       NO_IPV6 = YesPlease
        X = .exe
        COMPAT_OBJS += compat/cygwin.o
        UNRELIABLE_FSTAT = UnfortunatelyYes
@@ -864,6 +871,8 @@ ifeq ($(uname_S),FreeBSD)
                NO_UINTMAX_T = YesPlease
                NO_STRTOUMAX = YesPlease
        endif
+       PYTHON_PATH = /usr/local/bin/python
+       HAVE_PATHS_H = YesPlease
 endif
 ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
@@ -872,6 +881,7 @@ ifeq ($(uname_S),OpenBSD)
        NEEDS_LIBICONV = YesPlease
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
+       HAVE_PATHS_H = YesPlease
 endif
 ifeq ($(uname_S),NetBSD)
        ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
@@ -881,8 +891,10 @@ ifeq ($(uname_S),NetBSD)
        BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
        USE_ST_TIMESPEC = YesPlease
        NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
 endif
 ifeq ($(uname_S),AIX)
+       DEFAULT_PAGER = more
        NO_STRCASESTR=YesPlease
        NO_MEMMEM = YesPlease
        NO_MKDTEMP = YesPlease
@@ -901,6 +913,7 @@ ifeq ($(uname_S),GNU)
        # GNU/Hurd
        NO_STRLCPY=YesPlease
        NO_MKSTEMPS = YesPlease
+       HAVE_PATHS_H = YesPlease
 endif
 ifeq ($(uname_S),IRIX)
        NO_SETENV = YesPlease
@@ -1350,6 +1363,10 @@ else
        LIB_OBJS += thread-utils.o
 endif
 
+ifdef HAVE_PATHS_H
+       BASIC_CFLAGS += -DHAVE_PATHS_H
+endif
+
 ifdef DIR_HAS_BSD_GROUP_SEMANTICS
        COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
 endif
@@ -1476,7 +1493,7 @@ endif
 ifndef NO_PYTHON
        $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
 endif
-       $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
+       $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
 
 please_set_SHELL_PATH_to_a_more_modern_shell:
        @$$(:)
@@ -1558,18 +1575,29 @@ gitweb:
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
 
 ifdef JSMIN
-OTHER_PROGRAMS += gitweb/gitweb.cgi   gitweb/gitweb.min.js
-gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
+GITWEB_PROGRAMS += gitweb/gitweb.min.js
+GITWEB_JS = gitweb/gitweb.min.js
 else
-OTHER_PROGRAMS += gitweb/gitweb.cgi
-gitweb/gitweb.cgi: gitweb/gitweb.perl
+GITWEB_JS = gitweb/gitweb.js
 endif
+ifdef CSSMIN
+GITWEB_PROGRAMS += gitweb/gitweb.min.css
+GITWEB_CSS = gitweb/gitweb.min.css
+else
+GITWEB_CSS = gitweb/gitweb.css
+endif
+OTHER_PROGRAMS +=  gitweb/gitweb.cgi  $(GITWEB_PROGRAMS)
+gitweb/gitweb.cgi: gitweb/gitweb.perl $(GITWEB_PROGRAMS)
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
 
 ifdef JSMIN
 gitweb/gitweb.min.js: gitweb/gitweb.js
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
 endif # JSMIN
+ifdef CSSMIN
+gitweb/gitweb.min.css: gitweb/gitweb.css
+       $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
+endif # CSSMIN
 
 
 git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
@@ -1579,11 +1607,13 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.
            -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
            -e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \
            -e '/@@GITWEB_CGI@@/d' \
-           -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
+           -e '/@@GITWEB_CSS@@/r $(GITWEB_CSS)' \
            -e '/@@GITWEB_CSS@@/d' \
-           -e '/@@GITWEB_JS@@/r gitweb/gitweb.js' \
+           -e '/@@GITWEB_JS@@/r $(GITWEB_JS)' \
            -e '/@@GITWEB_JS@@/d' \
            -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
+            -e 's|@@GITWEB_CSS_NAME@@|$(GITWEB_CSS)|' \
+            -e 's|@@GITWEB_JS_NAME@@|$(GITWEB_JS)|' \
            $@.sh > $@+ && \
        chmod +x $@+ && \
        mv $@+ $@
@@ -1609,9 +1639,8 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
            -e '}' \
            -e 's|^import sys.*|&; \\\
                   import os; \\\
-                  sys.path[0] = os.environ.has_key("GITPYTHONLIB") and \\\
-                                os.environ["GITPYTHONLIB"] or \\\
-                                "@@INSTLIBDIR@@"|' \
+                  sys.path.insert(0, os.getenv("GITPYTHONLIB",\
+                                               "@@INSTLIBDIR@@"));|' \
            -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
            $@.py >$@+ && \
        chmod +x $@+ && \
@@ -1981,12 +2010,13 @@ endif
                ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
                cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
          done; } && \
-       { for p in $(REMOTE_CURL_ALIASES); do \
+       { test x"$(REMOTE_CURL_ALIASES)" = x || \
+               { for p in $(REMOTE_CURL_ALIASES); do \
                $(RM) "$$execdir/$$p" && \
                ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
                ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
                cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \
-         done; } && \
+         done; } ; } && \
        ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
 
 install-doc:
@@ -2083,7 +2113,7 @@ clean:
        $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
        $(MAKE) -C Documentation/ clean
 ifndef NO_PERL
-       $(RM) gitweb/gitweb.cgi
+       $(MAKE) -C gitweb clean
        $(MAKE) -C perl clean
 endif
 ifndef NO_PYTHON
index 00e7722..136c1b6 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.7.1.txt
\ No newline at end of file
+Documentation/RelNotes-1.7.1.1.txt
\ No newline at end of file
diff --git a/attr.c b/attr.c
index f5346ed..7467baf 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -594,20 +594,25 @@ static int path_matches(const char *pathname, int pathlen,
        return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
 }
 
+static int macroexpand_one(int attr_nr, int rem);
+
 static int fill_one(const char *what, struct match_attr *a, int rem)
 {
        struct git_attr_check *check = check_all_attr;
        int i;
 
-       for (i = 0; 0 < rem && i < a->num_attr; i++) {
+       for (i = a->num_attr - 1; 0 < rem && 0 <= i; i--) {
                struct git_attr *attr = a->state[i].attr;
                const char **n = &(check[attr->attr_nr].value);
                const char *v = a->state[i].setto;
 
                if (*n == ATTR__UNKNOWN) {
-                       debug_set(what, a->u.pattern, attr, v);
+                       debug_set(what,
+                                 a->is_macro ? a->u.attr->name : a->u.pattern,
+                                 attr, v);
                        *n = v;
                        rem--;
+                       rem = macroexpand_one(attr->attr_nr, rem);
                }
        }
        return rem;
@@ -629,19 +634,27 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
        return rem;
 }
 
-static int macroexpand(struct attr_stack *stk, int rem)
+static int macroexpand_one(int attr_nr, int rem)
 {
+       struct attr_stack *stk;
+       struct match_attr *a = NULL;
        int i;
-       struct git_attr_check *check = check_all_attr;
 
-       for (i = stk->num_matches - 1; 0 < rem && 0 <= i; i--) {
-               struct match_attr *a = stk->attrs[i];
-               if (!a->is_macro)
-                       continue;
-               if (check[a->u.attr->attr_nr].value != ATTR__TRUE)
-                       continue;
+       if (check_all_attr[attr_nr].value != ATTR__TRUE)
+               return rem;
+
+       for (stk = attr_stack; !a && stk; stk = stk->prev)
+               for (i = stk->num_matches - 1; !a && 0 <= i; i--) {
+                       struct match_attr *ma = stk->attrs[i];
+                       if (!ma->is_macro)
+                               continue;
+                       if (ma->u.attr->attr_nr == attr_nr)
+                               a = ma;
+               }
+
+       if (a)
                rem = fill_one("expand", a, rem);
-       }
+
        return rem;
 }
 
@@ -666,9 +679,6 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
                rem = fill(path, pathlen, stk, rem);
 
-       for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
-               rem = macroexpand(stk, rem);
-
        for (i = 0; i < num; i++) {
                const char *value = check_all_attr[check[i].attr->attr_nr].value;
                if (value == ATTR__UNKNOWN)
index 9e1f63e..2ab42aa 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -198,7 +198,7 @@ void create_branch(const char *head,
                log_all_ref_updates = 1;
 
        if (forcing)
-               snprintf(msg, sizeof msg, "branch: Reset from %s",
+               snprintf(msg, sizeof msg, "branch: Reset to %s",
                         start_name);
        else if (!dont_change_ref)
                snprintf(msg, sizeof msg, "branch: Created from %s",
index 65a594c..59bbcdb 100644 (file)
@@ -1864,13 +1864,13 @@ static int match_fragment(struct image *img,
                if (match_end && (preimage->nr + try_lno != img->nr))
                        return 0;
        } else if (ws_error_action == correct_ws_error &&
-                  (ws_rule & WS_BLANK_AT_EOF) && match_end) {
+                  (ws_rule & WS_BLANK_AT_EOF)) {
                /*
-                * This hunk that matches at the end extends beyond
-                * the end of img, and we are removing blank lines
-                * at the end of the file.  This many lines from the
-                * beginning of the preimage must match with img, and
-                * the remainder of the preimage must be blank.
+                * This hunk extends beyond the end of img, and we are
+                * removing blank lines at the end of the file.  This
+                * many lines from the beginning of the preimage must
+                * match with img, and the remainder of the preimage
+                * must be blank.
                 */
                preimage_limit = img->nr - try_lno;
        } else {
@@ -2824,11 +2824,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                if (stat_ret < 0) {
                        struct checkout costate;
                        /* checkout */
+                       memset(&costate, 0, sizeof(costate));
                        costate.base_dir = "";
-                       costate.base_dir_len = 0;
-                       costate.force = 0;
-                       costate.quiet = 0;
-                       costate.not_new = 0;
                        costate.refresh_cache = 1;
                        if (checkout_entry(*ce, &costate, NULL) ||
                            lstat(old_name, st))
index fc15863..8506286 100644 (file)
@@ -39,7 +39,7 @@ static int show_root;
 static int reverse;
 static int blank_boundary;
 static int incremental;
-static int xdl_opts = XDF_NEED_MINIMAL;
+static int xdl_opts;
 
 static enum date_mode blame_date_mode = DATE_ISO8601;
 static size_t blame_date_width;
@@ -1589,7 +1589,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
        strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
        printf("%s%c%d %d %d\n",
               hex,
-              ent->guilty ? ' ' : '*', // purely for debugging
+              ent->guilty ? ' ' : '*', /* purely for debugging */
               ent->s_lno + 1,
               ent->lno + 1,
               ent->num_lines);
index acefaaf..88b1f43 100644 (file)
@@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state)
        read_mmblob(&ours, active_cache[pos+1]->sha1);
        read_mmblob(&theirs, active_cache[pos+2]->sha1);
 
-       status = ll_merge(&result_buf, path, &ancestor,
+       status = ll_merge(&result_buf, path, &ancestor, "base",
                          &ours, "ours", &theirs, "theirs", 0);
        free(ancestor.ptr);
        free(ours.ptr);
@@ -439,6 +439,7 @@ static int merge_working_tree(struct checkout_opts *opts,
                        ret = reset_tree(new->commit->tree, opts, 1);
                        if (ret)
                                return ret;
+                       o.ancestor = old->name;
                        o.branch1 = new->name;
                        o.branch2 = "local";
                        merge_trees(&o, new->commit->tree, work,
index 05f8fb4..0bedde4 100644 (file)
@@ -302,6 +302,8 @@ static const struct ref *clone_local(const char *src_repo,
        transport = transport_get(remote, src_repo);
        ret = transport_get_remote_refs(transport);
        transport_disconnect(transport);
+       if (0 <= option_verbosity)
+               printf("done.\n");
        return ret;
 }
 
@@ -461,7 +463,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                die("could not create leading directories of '%s'", git_dir);
        set_git_dir(make_absolute_path(git_dir));
 
-       init_db(option_template, (option_verbosity < 0) ? INIT_DB_QUIET : 0);
+       if (0 <= option_verbosity)
+               printf("Cloning into %s...\n", get_git_dir());
+       init_db(option_template, INIT_DB_QUIET);
 
        /*
         * At this point, the config exists, so we do not need the
index 8dd104e..3c14ade 100644 (file)
@@ -307,7 +307,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         * (B) on failure, rollback the real index.
         */
        if (all || (also && pathspec && *pathspec)) {
-               int fd = hold_locked_index(&index_lock, 1);
+               fd = hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
@@ -322,8 +322,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         *
         * (1) return the name of the real index file.
         *
-        * The caller should run hooks on the real index, and run
-        * hooks on the real index, and create commit from the_index.
+        * The caller should run hooks on the real index,
+        * and create commit from the_index.
         * We still need to refresh the index here.
         */
        if (!pathspec || !*pathspec) {
@@ -1017,6 +1017,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
 int cmd_status(int argc, const char **argv, const char *prefix)
 {
        struct wt_status s;
+       int fd;
        unsigned char sha1[20];
        static struct option builtin_status_options[] = {
                OPT__VERBOSE(&verbose),
@@ -1050,6 +1051,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 
        read_cache_preload(s.pathspec);
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
+
+       fd = hold_locked_index(&index_lock, 0);
+       if (0 <= fd) {
+               if (!write_cache(fd, active_cache, active_nr))
+                       commit_locked_index(&index_lock);
+               rollback_lock_file(&index_lock);
+       }
+
        s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
        s.in_merge = in_merge;
        wt_status_collect(&s);
index 71be2a9..43caff2 100644 (file)
@@ -35,7 +35,8 @@ static const char *diff_index_args[] = {
 
 struct commit_name {
        struct tag *tag;
-       int prio; /* annotated tag = 2, tag = 1, head = 0 */
+       unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
+       unsigned name_checked:1;
        unsigned char sha1[20];
        char path[FLEX_ARRAY]; /* more */
 };
@@ -43,18 +44,53 @@ static const char *prio_names[] = {
        "head", "lightweight", "annotated",
 };
 
+static int replace_name(struct commit_name *e,
+                              int prio,
+                              const unsigned char *sha1,
+                              struct tag **tag)
+{
+       if (!e || e->prio < prio)
+               return 1;
+
+       if (e->prio == 2 && prio == 2) {
+               /* Multiple annotated tags point to the same commit.
+                * Select one to keep based upon their tagger date.
+                */
+               struct tag *t;
+
+               if (!e->tag) {
+                       t = lookup_tag(e->sha1);
+                       if (!t || parse_tag(t))
+                               return 1;
+                       e->tag = t;
+               }
+
+               t = lookup_tag(sha1);
+               if (!t || parse_tag(t))
+                       return 0;
+               *tag = t;
+
+               if (e->tag->date < t->date)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static void add_to_known_names(const char *path,
                               struct commit *commit,
                               int prio,
                               const unsigned char *sha1)
 {
        struct commit_name *e = commit->util;
-       if (!e || e->prio < prio) {
+       struct tag *tag = NULL;
+       if (replace_name(e, prio, sha1, &tag)) {
                size_t len = strlen(path)+1;
                free(e);
                e = xmalloc(sizeof(struct commit_name) + len);
-               e->tag = NULL;
+               e->tag = tag;
                e->prio = prio;
+               e->name_checked = 0;
                hashcpy(e->sha1, sha1);
                memcpy(e->path, path, len);
                commit->util = e;
@@ -165,10 +201,15 @@ static void display_name(struct commit_name *n)
 {
        if (n->prio == 2 && !n->tag) {
                n->tag = lookup_tag(n->sha1);
-               if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
+               if (!n->tag || parse_tag(n->tag))
                        die("annotated tag %s not available", n->path);
+       }
+       if (n->tag && !n->name_checked) {
+               if (!n->tag->tag)
+                       die("annotated tag %s has no embedded name", n->path);
                if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
                        warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
+               n->name_checked = 1;
        }
 
        if (n->tag)
index b0a4029..c6dd71a 100644 (file)
@@ -503,7 +503,7 @@ static void export_marks(char *file)
 
        f = fopen(file, "w");
        if (!f)
-               error("Unable to open marks file %s for writing.", file);
+               die_errno("Unable to open marks file %s for writing.", file);
 
        for (i = 0; i < idnums.size; i++) {
                if (deco->base && deco->base->type == 1) {
index 957be9f..8470850 100644 (file)
 #include "transport.h"
 
 static const char * const builtin_fetch_usage[] = {
-       "git fetch [options] [<repository> <refspec>...]",
-       "git fetch [options] <group>",
-       "git fetch --multiple [options] [<repository> | <group>]...",
-       "git fetch --all [options]",
+       "git fetch [<options>] [<repository> [<refspec>...]]",
+       "git fetch [<options>] <group>",
+       "git fetch --multiple [<options>] [<repository> | <group>]...",
+       "git fetch --all [<options>]",
        NULL
 };
 
index 9d52400..379a031 100644 (file)
@@ -4,6 +4,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "tag.h"
+#include "string-list.h"
 
 static const char * const fmt_merge_msg_usage[] = {
        "git fmt-merge-msg [--log|--no-log] [--file <file>]",
@@ -24,58 +25,21 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
        return 0;
 }
 
-struct list {
-       char **list;
-       void **payload;
-       unsigned nr, alloc;
+struct src_data {
+       struct string_list branch, tag, r_branch, generic;
+       int head_status;
 };
 
-static void append_to_list(struct list *list, char *value, void *payload)
-{
-       if (list->nr == list->alloc) {
-               list->alloc += 32;
-               list->list = xrealloc(list->list, sizeof(char *) * list->alloc);
-               list->payload = xrealloc(list->payload,
-                               sizeof(char *) * list->alloc);
-       }
-       list->payload[list->nr] = payload;
-       list->list[list->nr++] = value;
-}
-
-static int find_in_list(struct list *list, char *value)
-{
-       int i;
-
-       for (i = 0; i < list->nr; i++)
-               if (!strcmp(list->list[i], value))
-                       return i;
-
-       return -1;
-}
-
-static void free_list(struct list *list)
+void init_src_data(struct src_data *data)
 {
-       int i;
-
-       if (list->alloc == 0)
-               return;
-
-       for (i = 0; i < list->nr; i++) {
-               free(list->list[i]);
-               free(list->payload[i]);
-       }
-       free(list->list);
-       free(list->payload);
-       list->nr = list->alloc = 0;
+       data->branch.strdup_strings = 1;
+       data->tag.strdup_strings = 1;
+       data->r_branch.strdup_strings = 1;
+       data->generic.strdup_strings = 1;
 }
 
-struct src_data {
-       struct list branch, tag, r_branch, generic;
-       int head_status;
-};
-
-static struct list srcs = { NULL, NULL, 0, 0};
-static struct list origins = { NULL, NULL, 0, 0};
+static struct string_list srcs = { NULL, 0, 0, 1 };
+static struct string_list origins = { NULL, 0, 0, 1 };
 
 static int handle_line(char *line)
 {
@@ -83,6 +47,7 @@ static int handle_line(char *line)
        unsigned char *sha1;
        char *src, *origin;
        struct src_data *src_data;
+       struct string_list_item *item;
        int pulling_head = 0;
 
        if (len < 43 || line[40] != '\t')
@@ -115,64 +80,62 @@ static int handle_line(char *line)
                pulling_head = 1;
        }
 
-       i = find_in_list(&srcs, src);
-       if (i < 0) {
-               i = srcs.nr;
-               append_to_list(&srcs, xstrdup(src),
-                               xcalloc(1, sizeof(struct src_data)));
+       item = unsorted_string_list_lookup(&srcs, src);
+       if (!item) {
+               item = string_list_append(src, &srcs);
+               item->util = xcalloc(1, sizeof(struct src_data));
+               init_src_data(item->util);
        }
-       src_data = srcs.payload[i];
+       src_data = item->util;
 
        if (pulling_head) {
-               origin = xstrdup(src);
+               origin = src;
                src_data->head_status |= 1;
        } else if (!prefixcmp(line, "branch ")) {
-               origin = xstrdup(line + 7);
-               append_to_list(&src_data->branch, origin, NULL);
+               origin = line + 7;
+               string_list_append(origin, &src_data->branch);
                src_data->head_status |= 2;
        } else if (!prefixcmp(line, "tag ")) {
                origin = line;
-               append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
+               string_list_append(origin + 4, &src_data->tag);
                src_data->head_status |= 2;
        } else if (!prefixcmp(line, "remote branch ")) {
-               origin = xstrdup(line + 14);
-               append_to_list(&src_data->r_branch, origin, NULL);
+               origin = line + 14;
+               string_list_append(origin, &src_data->r_branch);
                src_data->head_status |= 2;
        } else {
-               origin = xstrdup(src);
-               append_to_list(&src_data->generic, xstrdup(line), NULL);
+               origin = src;
+               string_list_append(line, &src_data->generic);
                src_data->head_status |= 2;
        }
 
        if (!strcmp(".", src) || !strcmp(src, origin)) {
                int len = strlen(origin);
-               if (origin[0] == '\'' && origin[len - 1] == '\'') {
+               if (origin[0] == '\'' && origin[len - 1] == '\'')
                        origin = xmemdupz(origin + 1, len - 2);
-               } else {
-                       origin = xstrdup(origin);
-               }
        } else {
                char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
                sprintf(new_origin, "%s of %s", origin, src);
                origin = new_origin;
        }
-       append_to_list(&origins, origin, sha1);
+       string_list_append(origin, &origins)->util = sha1;
        return 0;
 }
 
 static void print_joined(const char *singular, const char *plural,
-               struct list *list, struct strbuf *out)
+               struct string_list *list, struct strbuf *out)
 {
        if (list->nr == 0)
                return;
        if (list->nr == 1) {
-               strbuf_addf(out, "%s%s", singular, list->list[0]);
+               strbuf_addf(out, "%s%s", singular, list->items[0].string);
        } else {
                int i;
                strbuf_addstr(out, plural);
                for (i = 0; i < list->nr - 1; i++)
-                       strbuf_addf(out, "%s%s", i > 0 ? ", " : "", list->list[i]);
-               strbuf_addf(out, " and %s", list->list[list->nr - 1]);
+                       strbuf_addf(out, "%s%s", i > 0 ? ", " : "",
+                                   list->items[i].string);
+               strbuf_addf(out, " and %s", list->items[list->nr - 1].string);
        }
 }
 
@@ -183,8 +146,9 @@ static void shortlog(const char *name, unsigned char *sha1,
        int i, count = 0;
        struct commit *commit;
        struct object *branch;
-       struct list subjects = { NULL, NULL, 0, 0 };
+       struct string_list subjects = { NULL, 0, 0, 1 };
        int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
+       struct strbuf sb = STRBUF_INIT;
 
        branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
        if (!branch || branch->type != OBJ_COMMIT)
@@ -198,7 +162,7 @@ static void shortlog(const char *name, unsigned char *sha1,
        if (prepare_revision_walk(rev))
                die("revision walk setup failed");
        while ((commit = get_revision(rev)) != NULL) {
-               char *oneline, *bol, *eol;
+               struct pretty_print_context ctx = {0};
 
                /* ignore merges */
                if (commit->parents && commit->parents->next)
@@ -208,30 +172,14 @@ static void shortlog(const char *name, unsigned char *sha1,
                if (subjects.nr > limit)
                        continue;
 
-               bol = strstr(commit->buffer, "\n\n");
-               if (bol) {
-                       unsigned char c;
-                       do {
-                               c = *++bol;
-                       } while (isspace(c));
-                       if (!c)
-                               bol = NULL;
-               }
-
-               if (!bol) {
-                       append_to_list(&subjects, xstrdup(sha1_to_hex(
-                                                       commit->object.sha1)),
-                                       NULL);
-                       continue;
-               }
+               format_commit_message(commit, "%s", &sb, &ctx);
+               strbuf_ltrim(&sb);
 
-               eol = strchr(bol, '\n');
-               if (eol) {
-                       oneline = xmemdupz(bol, eol - bol);
-               } else {
-                       oneline = xstrdup(bol);
-               }
-               append_to_list(&subjects, oneline, NULL);
+               if (!sb.len)
+                       string_list_append(sha1_to_hex(commit->object.sha1),
+                                          &subjects);
+               else
+                       string_list_append(strbuf_detach(&sb, NULL), &subjects);
        }
 
        if (count > limit)
@@ -243,7 +191,7 @@ static void shortlog(const char *name, unsigned char *sha1,
                if (i >= limit)
                        strbuf_addf(out, "  ...\n");
                else
-                       strbuf_addf(out, "  %s\n", subjects.list[i]);
+                       strbuf_addf(out, "  %s\n", subjects.items[i].string);
 
        clear_commit_marks((struct commit *)branch, flags);
        clear_commit_marks(head, flags);
@@ -251,7 +199,7 @@ static void shortlog(const char *name, unsigned char *sha1,
        rev->commits = NULL;
        rev->pending.nr = 0;
 
-       free_list(&subjects);
+       string_list_clear(&subjects, 0);
 }
 
 int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
@@ -281,16 +229,19 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
                        die ("Error in line %d: %.*s", i, len, p);
        }
 
+       if (!srcs.nr)
+               return 0;
+
        strbuf_addstr(out, "Merge ");
        for (i = 0; i < srcs.nr; i++) {
-               struct src_data *src_data = srcs.payload[i];
+               struct src_data *src_data = srcs.items[i].util;
                const char *subsep = "";
 
                strbuf_addstr(out, sep);
                sep = "; ";
 
                if (src_data->head_status == 1) {
-                       strbuf_addstr(out, srcs.list[i]);
+                       strbuf_addstr(out, srcs.items[i].string);
                        continue;
                }
                if (src_data->head_status == 3) {
@@ -319,8 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
                        print_joined("commit ", "commits ", &src_data->generic,
                                        out);
                }
-               if (strcmp(".", srcs.list[i]))
-                       strbuf_addf(out, " of %s", srcs.list[i]);
+               if (strcmp(".", srcs.items[i].string))
+                       strbuf_addf(out, " of %s", srcs.items[i].string);
        }
 
        if (!strcmp("master", current_branch))
@@ -339,7 +290,7 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
                rev.limited = 1;
 
                for (i = 0; i < origins.nr; i++)
-                       shortlog(origins.list[i], origins.payload[i],
+                       shortlog(origins.items[i].string, origins.items[i].util,
                                        head, &rev, limit, out);
        }
        return 0;
@@ -350,7 +301,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        const char *inpath = NULL;
        struct option options[] = {
                OPT_BOOLEAN(0, "log",     &merge_summary, "populate log with the shortlog"),
-               OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
+               { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL,
+                 "alias for --log (deprecated)",
+                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_FILENAME('F', "file", &inpath, "file to read from"),
                OPT_END()
        };
index 62be1bb..7f5011f 100644 (file)
@@ -549,10 +549,10 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
                grab_person("committer", val, deref, obj, buf, sz);
                break;
        case OBJ_TREE:
-               // grab_tree_values(val, deref, obj, buf, sz);
+               /* grab_tree_values(val, deref, obj, buf, sz); */
                break;
        case OBJ_BLOB:
-               // grab_blob_values(val, deref, obj, buf, sz);
+               /* grab_blob_values(val, deref, obj, buf, sz); */
                break;
        default:
                die("Eh?  Object of type %d?", obj->type);
index 9d30ddb..b194ea3 100644 (file)
@@ -17,8 +17,8 @@
 #include "dir.h"
 
 #ifndef NO_PTHREADS
-#include "thread-utils.h"
 #include <pthread.h>
+#include "thread-utils.h"
 #endif
 
 static char const * const grep_usage[] = {
@@ -96,6 +96,9 @@ static pthread_cond_t cond_write;
 /* Signalled when we are finished with everything. */
 static pthread_cond_t cond_result;
 
+static int print_hunk_marks_between_files;
+static int printed_something;
+
 static void add_work(enum work_type type, char *name, void *id)
 {
        grep_lock();
@@ -159,7 +162,12 @@ static void work_done(struct work_item *w)
        for(; todo[todo_done].done && todo_done != todo_start;
            todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
                w = &todo[todo_done];
-               write_or_die(1, w->out.buf, w->out.len);
+               if (w->out.len) {
+                       if (print_hunk_marks_between_files && printed_something)
+                               write_or_die(1, "--\n", 3);
+                       write_or_die(1, w->out.buf, w->out.len);
+                       printed_something = 1;
+               }
                free(w->name);
                free(w->identifier);
        }
@@ -946,8 +954,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (online_cpus() == 1 || !grep_threads_ok(&opt))
                use_threads = 0;
 
-       if (use_threads)
+       if (use_threads) {
+               if (opt.pre_context || opt.post_context)
+                       print_hunk_marks_between_files = 1;
                start_threads(&opt);
+       }
 #else
        use_threads = 0;
 #endif
index b4cf8c5..a89ae83 100644 (file)
@@ -11,7 +11,7 @@
 #include "exec_cmd.h"
 
 static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git index-pack [-v] [-o <index-file>] [{ --keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
 
 struct object_entry
 {
@@ -266,26 +266,23 @@ static void unlink_base_data(struct base_data *c)
 
 static void *unpack_entry_data(unsigned long offset, unsigned long size)
 {
+       int status;
        z_stream stream;
        void *buf = xmalloc(size);
 
        memset(&stream, 0, sizeof(stream));
+       git_inflate_init(&stream);
        stream.next_out = buf;
        stream.avail_out = size;
-       stream.next_in = fill(1);
-       stream.avail_in = input_len;
-       git_inflate_init(&stream);
 
-       for (;;) {
-               int ret = git_inflate(&stream, 0);
-               use(input_len - stream.avail_in);
-               if (stream.total_out == size && ret == Z_STREAM_END)
-                       break;
-               if (ret != Z_OK)
-                       bad_object(offset, "inflate returned %d", ret);
+       do {
                stream.next_in = fill(1);
                stream.avail_in = input_len;
-       }
+               status = git_inflate(&stream, 0);
+               use(input_len - stream.avail_in);
+       } while (status == Z_OK);
+       if (stream.total_out != size || status != Z_STREAM_END)
+               bad_object(offset, "inflate returned %d", status);
        git_inflate_end(&stream);
        return buf;
 }
@@ -359,34 +356,38 @@ static void *get_data_from_pack(struct object_entry *obj)
 {
        off_t from = obj[0].idx.offset + obj[0].hdr_size;
        unsigned long len = obj[1].idx.offset - from;
-       unsigned long rdy = 0;
-       unsigned char *src, *data;
+       unsigned char *data, *inbuf;
        z_stream stream;
-       int st;
+       int status;
 
-       src = xmalloc(len);
-       data = src;
-       do {
-               ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
-               if (n < 0)
-                       die_errno("cannot pread pack file");
-               if (!n)
-                       die("premature end of pack file, %lu bytes missing",
-                           len - rdy);
-               rdy += n;
-       } while (rdy < len);
        data = xmalloc(obj->size);
+       inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
+
        memset(&stream, 0, sizeof(stream));
+       git_inflate_init(&stream);
        stream.next_out = data;
        stream.avail_out = obj->size;
-       stream.next_in = src;
-       stream.avail_in = len;
-       git_inflate_init(&stream);
-       while ((st = git_inflate(&stream, Z_FINISH)) == Z_OK);
-       git_inflate_end(&stream);
-       if (st != Z_STREAM_END || stream.total_out != obj->size)
+
+       do {
+               ssize_t n = (len < 64*1024) ? len : 64*1024;
+               n = pread(pack_fd, inbuf, n, from);
+               if (n < 0)
+                       die_errno("cannot pread pack file");
+               if (!n)
+                       die("premature end of pack file, %lu bytes missing", len);
+               from += n;
+               len -= n;
+               stream.next_in = inbuf;
+               stream.avail_in = n;
+               status = git_inflate(&stream, 0);
+       } while (len && status == Z_OK && !stream.avail_in);
+
+       /* This has been inflated OK when first encountered, so... */
+       if (status != Z_STREAM_END || stream.total_out != obj->size)
                die("serious inflate inconsistency");
-       free(src);
+
+       git_inflate_end(&stream);
+       free(inbuf);
        return data;
 }
 
@@ -668,25 +669,25 @@ static void parse_pack_objects(unsigned char *sha1)
 static int write_compressed(struct sha1file *f, void *in, unsigned int size)
 {
        z_stream stream;
-       unsigned long maxsize;
-       void *out;
+       int status;
+       unsigned char outbuf[4096];
 
        memset(&stream, 0, sizeof(stream));
        deflateInit(&stream, zlib_compression_level);
-       maxsize = deflateBound(&stream, size);
-       out = xmalloc(maxsize);
-
-       /* Compress it */
        stream.next_in = in;
        stream.avail_in = size;
-       stream.next_out = out;
-       stream.avail_out = maxsize;
-       while (deflate(&stream, Z_FINISH) == Z_OK);
-       deflateEnd(&stream);
 
+       do {
+               stream.next_out = outbuf;
+               stream.avail_out = sizeof(outbuf);
+               status = deflate(&stream, Z_FINISH);
+               sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
+       } while (status == Z_OK);
+
+       if (status != Z_STREAM_END)
+               die("unable to deflate appended object (%d)", status);
        size = stream.total_out;
-       sha1write(f, out, size);
-       free(out);
+       deflateEnd(&stream);
        return size;
 }
 
index edc40ff..0271285 100644 (file)
@@ -463,7 +463,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                static char git_dir[PATH_MAX+1];
 
                setenv(GIT_DIR_ENVIRONMENT,
-                       getcwd(git_dir, sizeof(git_dir)), 0);
+                       getcwd(git_dir, sizeof(git_dir)), argc > 0);
        }
 
        if (init_shared_repository != -1)
index a8dd8c9..6208703 100644 (file)
@@ -36,6 +36,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 {
        int i;
        int decoration_style = 0;
+       struct userformat_want w;
 
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
@@ -58,7 +59,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
                usage(builtin_log_usage);
        argc = setup_revisions(argc, argv, rev, opt);
 
-       if (!rev->show_notes_given && !rev->pretty_given)
+       memset(&w, 0, sizeof(w));
+       userformat_find_requirements(NULL, &w);
+
+       if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
                rev->show_notes = 1;
        if (rev->show_notes)
                init_display_notes(&rev->notes_opt);
@@ -1157,8 +1161,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        return 0;
        }
 
-       if (ignore_if_in_upstream)
+       if (ignore_if_in_upstream) {
+               /* Don't say anything if head and upstream are the same. */
+               if (rev.pending.nr == 2) {
+                       struct object_array_entry *o = rev.pending.objects;
+                       if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
+                               return 0;
+               }
                get_patch_ids(&rev, &ids, prefix);
+       }
 
        if (!use_stdout)
                realstdout = xfdopen(xdup(1), "w");
@@ -1296,8 +1307,11 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
        return -1;
 }
 
-static const char cherry_usage[] =
-"git cherry [-v] [<upstream> [<head> [<limit>]]]";
+static const char * const cherry_usage[] = {
+       "git cherry [-v] [<upstream> [<head> [<limit>]]]",
+       NULL
+};
+
 int cmd_cherry(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
@@ -1308,26 +1322,25 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
        const char *upstream;
        const char *head = "HEAD";
        const char *limit = NULL;
-       int verbose = 0;
+       int verbose = 0, abbrev = 0;
 
-       if (argc > 1 && !strcmp(argv[1], "-v")) {
-               verbose = 1;
-               argc--;
-               argv++;
-       }
+       struct option options[] = {
+               OPT__ABBREV(&abbrev),
+               OPT__VERBOSE(&verbose),
+               OPT_END()
+       };
 
-       if (argc > 1 && !strcmp(argv[1], "-h"))
-               usage(cherry_usage);
+       argc = parse_options(argc, argv, prefix, options, cherry_usage, 0);
 
        switch (argc) {
-       case 4:
-               limit = argv[3];
-               /* FALLTHROUGH */
        case 3:
-               head = argv[2];
+               limit = argv[2];
                /* FALLTHROUGH */
        case 2:
-               upstream = argv[1];
+               head = argv[1];
+               /* FALLTHROUGH */
+       case 1:
+               upstream = argv[0];
                break;
        default:
                current_branch = branch_get(NULL);
@@ -1337,7 +1350,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                        fprintf(stderr, "Could not find a tracked"
                                        " remote branch, please"
                                        " specify <upstream> manually.\n");
-                       usage(cherry_usage);
+                       usage_with_options(cherry_usage, options);
                }
 
                upstream = current_branch->merge[0]->dst;
@@ -1390,12 +1403,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                        pretty_print_commit(CMIT_FMT_ONELINE, commit,
                                            &buf, &ctx);
                        printf("%c %s %s\n", sign,
-                              sha1_to_hex(commit->object.sha1), buf.buf);
+                              find_unique_abbrev(commit->object.sha1, abbrev),
+                              buf.buf);
                        strbuf_release(&buf);
                }
                else {
                        printf("%c %s\n", sign,
-                              sha1_to_hex(commit->object.sha1));
+                              find_unique_abbrev(commit->object.sha1, abbrev));
                }
 
                list = list->next;
index b065061..c0fbcdc 100644 (file)
@@ -153,8 +153,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
                printf("%s%06o %s %d\t",
                       tag,
                       ce->ce_mode,
-                      abbrev ? find_unique_abbrev(ce->sha1,abbrev)
-                               : sha1_to_hex(ce->sha1),
+                      find_unique_abbrev(ce->sha1,abbrev),
                       ce_stage(ce));
        }
        write_name_quoted(ce->name + offset, stdout, line_terminator);
@@ -176,9 +175,7 @@ static int show_one_ru(struct string_list_item *item, void *cbdata)
                if (!ui->mode[i])
                        continue;
                printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
-                      abbrev
-                      ? find_unique_abbrev(ui->sha1[i], abbrev)
-                      : sha1_to_hex(ui->sha1[i]),
+                      find_unique_abbrev(ui->sha1[i], abbrev),
                       i + 1);
                write_name_quoted(path + offset, stdout, line_terminator);
        }
index 4484185..dc86b0d 100644 (file)
@@ -103,13 +103,11 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
                        } else
                                strcpy(size_text, "-");
                        printf("%06o %s %s %7s\t", mode, type,
-                              abbrev ? find_unique_abbrev(sha1, abbrev)
-                                     : sha1_to_hex(sha1),
+                              find_unique_abbrev(sha1, abbrev),
                               size_text);
                } else
                        printf("%06o %s %s\t", mode, type,
-                              abbrev ? find_unique_abbrev(sha1, abbrev)
-                                     : sha1_to_hex(sha1));
+                              find_unique_abbrev(sha1, abbrev));
        }
        write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
                          pathname, stdout, line_termination);
index ce2ef6b..4a9729b 100644 (file)
@@ -746,7 +746,8 @@ static int is_scissors_line(const struct strbuf *line)
                        continue;
                }
                if (i + 1 < len &&
-                   (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) {
+                   (!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2) ||
+                    !memcmp(buf + i, ">%", 2) || !memcmp(buf + i, "%<", 2))) {
                        in_perforation = 1;
                        perforation += 2;
                        scissors += 2;
index 69cc683..b8e9e5b 100644 (file)
@@ -25,7 +25,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        const char *names[3] = { NULL, NULL, NULL };
        mmfile_t mmfs[3];
        mmbuffer_t result = {NULL, 0};
-       xmparam_t xmp = {{XDF_NEED_MINIMAL}};
+       xmparam_t xmp = {{0}};
        int ret = 0, i = 0, to_stdout = 0;
        int quiet = 0;
        int nongit;
@@ -77,8 +77,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
                                        argv[i]);
        }
 
-       ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
-                       &xmp, &result);
+       xmp.ancestor = names[1];
+       xmp.file1 = names[0];
+       xmp.file2 = names[2];
+       ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
 
        for (i = 0; i < 3; i++)
                free(mmfs[i].ptr);
index a4a4f2c..fc00d79 100644 (file)
@@ -106,7 +106,7 @@ static void show_diff(struct merge_list *entry)
        xdemitconf_t xecfg;
        xdemitcb_t ecb;
 
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = 0;
        memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
        ecb.outf = show_outf;
index 3aaec7b..c043066 100644 (file)
@@ -667,7 +667,7 @@ static int count_unmerged_entries(void)
        return ret;
 }
 
-static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
+int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)
 {
        struct tree *trees[MAX_UNPACK_TREES];
        struct unpack_trees_options opts;
index 4543d11..2661754 100644 (file)
 #include "string-list.h"
 
 static const char * const git_notes_usage[] = {
+       "git notes [--ref <notes_ref>] [list [<object>]]",
+       "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+       "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
+       "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+       "git notes [--ref <notes_ref>] edit [<object>]",
+       "git notes [--ref <notes_ref>] show [<object>]",
+       "git notes [--ref <notes_ref>] remove [<object>]",
+       "git notes [--ref <notes_ref>] prune",
+       NULL
+};
+
+static const char * const git_notes_list_usage[] = {
        "git notes [list [<object>]]",
-       "git notes add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
-       "git notes copy [-f] <from-object> <to-object>",
-       "git notes append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
+       NULL
+};
+
+static const char * const git_notes_add_usage[] = {
+       "git notes add [<options>] [<object>]",
+       NULL
+};
+
+static const char * const git_notes_copy_usage[] = {
+       "git notes copy [<options>] <from-object> <to-object>",
+       "git notes copy --stdin [<from-object> <to-object>]...",
+       NULL
+};
+
+static const char * const git_notes_append_usage[] = {
+       "git notes append [<options>] [<object>]",
+       NULL
+};
+
+static const char * const git_notes_edit_usage[] = {
        "git notes edit [<object>]",
+       NULL
+};
+
+static const char * const git_notes_show_usage[] = {
        "git notes show [<object>]",
+       NULL
+};
+
+static const char * const git_notes_remove_usage[] = {
        "git notes remove [<object>]",
+       NULL
+};
+
+static const char * const git_notes_prune_usage[] = {
        "git notes prune",
        NULL
 };
@@ -272,7 +313,6 @@ int commit_notes(struct notes_tree *t, const char *msg)
        return 0;
 }
 
-
 combine_notes_fn *parse_combine_notes_fn(const char *v)
 {
        if (!strcasecmp(v, "overwrite"))
@@ -376,7 +416,7 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd)
 {
        struct strbuf buf = STRBUF_INIT;
        struct notes_rewrite_cfg *c = NULL;
-       struct notes_tree *t;
+       struct notes_tree *t = NULL;
        int ret = 0;
 
        if (rewrite_cmd) {
@@ -427,22 +467,65 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd)
        return ret;
 }
 
-int cmd_notes(int argc, const char **argv, const char *prefix)
+static struct notes_tree *init_notes_check(const char *subcommand)
 {
        struct notes_tree *t;
-       unsigned char object[20], from_obj[20], new_note[20];
+       init_notes(NULL, NULL, NULL, 0);
+       t = &default_notes_tree;
+
+       if (prefixcmp(t->ref, "refs/notes/"))
+               die("Refusing to %s notes in %s (outside of refs/notes/)",
+                   subcommand, t->ref);
+       return t;
+}
+
+static int list(int argc, const char **argv, const char *prefix)
+{
+       struct notes_tree *t;
+       unsigned char object[20];
        const unsigned char *note;
+       int retval = -1;
+       struct option options[] = {
+               OPT_END()
+       };
+
+       if (argc)
+               argc = parse_options(argc, argv, prefix, options,
+                                    git_notes_list_usage, 0);
+
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_list_usage, options);
+       }
+
+       t = init_notes_check("list");
+       if (argc) {
+               if (get_sha1(argv[0], object))
+                       die("Failed to resolve '%s' as a valid ref.", argv[0]);
+               note = get_note(t, object);
+               if (note) {
+                       puts(sha1_to_hex(note));
+                       retval = 0;
+               } else
+                       retval = error("No note found for object %s.",
+                                      sha1_to_hex(object));
+       } else
+               retval = for_each_note(t, 0, list_each_note, NULL);
+
+       free_notes(t);
+       return retval;
+}
+
+static int add(int argc, const char **argv, const char *prefix)
+{
+       int retval = 0, force = 0;
        const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20], new_note[20];
        char logmsg[100];
-
-       int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,
-           remove = 0, prune = 0, force = 0, from_stdin = 0;
-       int given_object = 0, i = 1, retval = 0;
+       const unsigned char *note;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
-       const char *rewrite_cmd = NULL;
-       const char *override_notes_ref = NULL;
        struct option options[] = {
-               OPT_GROUP("Notes contents options"),
                { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
                        "note contents as a string", PARSE_OPT_NONEG,
                        parse_msg_arg},
@@ -455,196 +538,325 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
                        "reuse specified note object", PARSE_OPT_NONEG,
                        parse_reuse_arg},
-               OPT_GROUP("Other options"),
                OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
-               OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
-               OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
-                          "use notes from <notes_ref>"),
-               OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
-                          "load rewriting config for <command> (implies --stdin)"),
                OPT_END()
        };
 
-       git_config(git_default_config, NULL);
-
-       argc = parse_options(argc, argv, prefix, options, git_notes_usage, 0);
+       argc = parse_options(argc, argv, prefix, options, git_notes_add_usage,
+                            0);
 
-       if (override_notes_ref) {
-               struct strbuf sb = STRBUF_INIT;
-               if (!prefixcmp(override_notes_ref, "refs/notes/"))
-                       /* we're happy */;
-               else if (!prefixcmp(override_notes_ref, "notes/"))
-                       strbuf_addstr(&sb, "refs/");
-               else
-                       strbuf_addstr(&sb, "refs/notes/");
-               strbuf_addstr(&sb, override_notes_ref);
-               setenv("GIT_NOTES_REF", sb.buf, 1);
-               strbuf_release(&sb);
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_add_usage, options);
        }
 
-       if (argc && !strcmp(argv[0], "list"))
-               list = 1;
-       else if (argc && !strcmp(argv[0], "add"))
-               add = 1;
-       else if (argc && !strcmp(argv[0], "copy"))
-               copy = 1;
-       else if (argc && !strcmp(argv[0], "append"))
-               append = 1;
-       else if (argc && !strcmp(argv[0], "edit"))
-               edit = 1;
-       else if (argc && !strcmp(argv[0], "show"))
-               show = 1;
-       else if (argc && !strcmp(argv[0], "remove"))
-               remove = 1;
-       else if (argc && !strcmp(argv[0], "prune"))
-               prune = 1;
-       else if (!argc) {
-               list = 1; /* Default to 'list' if no other subcommand given */
-               i = 0;
-       }
+       object_ref = argc ? argv[0] : "HEAD";
 
-       if (list + add + copy + append + edit + show + remove + prune != 1)
-               usage_with_options(git_notes_usage, options);
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
 
-       if (msg.given && !(add || append || edit)) {
-               error("cannot use -m/-F/-c/-C options with %s subcommand.",
-                     argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
+       t = init_notes_check("add");
+       note = get_note(t, object);
 
-       if (msg.given && edit) {
-               fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
-                       "for the 'edit' subcommand.\n"
-                       "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
+       if (note) {
+               if (!force) {
+                       retval = error("Cannot add notes. Found existing notes "
+                                      "for object %s. Use '-f' to overwrite "
+                                      "existing notes", sha1_to_hex(object));
+                       goto out;
+               }
+               fprintf(stderr, "Overwriting existing notes for object %s\n",
+                       sha1_to_hex(object));
        }
 
-       if (force && !(add || copy)) {
-               error("cannot use -f option with %s subcommand.", argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
+       create_note(object, &msg, 0, note, new_note);
 
-       if (!copy && rewrite_cmd) {
-               error("cannot use --for-rewrite with %s subcommand.", argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
-       if (!copy && from_stdin) {
-               error("cannot use --stdin with %s subcommand.", argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
+       if (is_null_sha1(new_note))
+               remove_note(t, object);
+       else
+               add_note(t, object, new_note, combine_notes_overwrite);
 
-       if (copy) {
-               const char *from_ref;
-               if (from_stdin || rewrite_cmd) {
-                       if (argc > 1) {
-                               error("too many parameters");
-                               usage_with_options(git_notes_usage, options);
-                       } else {
-                               return notes_copy_from_stdin(force, rewrite_cmd);
-                       }
-               }
-               if (argc < 3) {
-                       error("too few parameters");
-                       usage_with_options(git_notes_usage, options);
+       snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
+                is_null_sha1(new_note) ? "removed" : "added", "add");
+       commit_notes(t, logmsg);
+out:
+       free_notes(t);
+       strbuf_release(&(msg.buf));
+       return retval;
+}
+
+static int copy(int argc, const char **argv, const char *prefix)
+{
+       int retval = 0, force = 0, from_stdin = 0;
+       const unsigned char *from_note, *note;
+       const char *object_ref;
+       unsigned char object[20], from_obj[20];
+       struct notes_tree *t;
+       const char *rewrite_cmd = NULL;
+       struct option options[] = {
+               OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
+               OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
+               OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
+                          "load rewriting config for <command> (implies "
+                          "--stdin)"),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage,
+                            0);
+
+       if (from_stdin || rewrite_cmd) {
+               if (argc) {
+                       error("too many parameters");
+                       usage_with_options(git_notes_copy_usage, options);
+               } else {
+                       return notes_copy_from_stdin(force, rewrite_cmd);
                }
-               from_ref = argv[i++];
-               if (get_sha1(from_ref, from_obj))
-                       die("Failed to resolve '%s' as a valid ref.", from_ref);
        }
 
-       given_object = argc > i;
-       object_ref = given_object ? argv[i++] : "HEAD";
-
-       if (argc > i || (prune && given_object)) {
+       if (2 < argc) {
                error("too many parameters");
-               usage_with_options(git_notes_usage, options);
+               usage_with_options(git_notes_copy_usage, options);
        }
 
-       if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+       if (get_sha1(argv[0], from_obj))
+               die("Failed to resolve '%s' as a valid ref.", argv[0]);
 
-       init_notes(NULL, NULL, NULL, 0);
-       t = &default_notes_tree;
+       object_ref = 1 < argc ? argv[1] : "HEAD";
 
-       if (prefixcmp(t->ref, "refs/notes/"))
-               die("Refusing to %s notes in %s (outside of refs/notes/)",
-                   argv[0], t->ref);
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
 
+       t = init_notes_check("copy");
        note = get_note(t, object);
 
-       /* list command */
-
-       if (list) {
-               if (given_object) {
-                       if (note) {
-                               puts(sha1_to_hex(note));
-                               goto end;
-                       }
-               } else {
-                       retval = for_each_note(t, 0, list_each_note, NULL);
-                       goto end;
+       if (note) {
+               if (!force) {
+                       retval = error("Cannot copy notes. Found existing "
+                                      "notes for object %s. Use '-f' to "
+                                      "overwrite existing notes",
+                                      sha1_to_hex(object));
+                       goto out;
                }
+               fprintf(stderr, "Overwriting existing notes for object %s\n",
+                       sha1_to_hex(object));
        }
 
-       /* show command */
-
-       if ((list || show) && !note) {
-               error("No note found for object %s.", sha1_to_hex(object));
-               retval = 1;
-               goto end;
-       } else if (show) {
-               const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
-               retval = execv_git_cmd(show_args);
-               goto end;
+       from_note = get_note(t, from_obj);
+       if (!from_note) {
+               retval = error("Missing notes on source object %s. Cannot "
+                              "copy.", sha1_to_hex(from_obj));
+               goto out;
        }
 
-       /* add/append/edit/remove/prune command */
+       add_note(t, object, from_note, combine_notes_overwrite);
+       commit_notes(t, "Notes added by 'git notes copy'");
+out:
+       free_notes(t);
+       return retval;
+}
 
-       if ((add || copy) && note) {
-               if (!force) {
-                       error("Cannot %s notes. Found existing notes for object"
-                             " %s. Use '-f' to overwrite existing notes",
-                             argv[0], sha1_to_hex(object));
-                       retval = 1;
-                       goto end;
-               }
-               fprintf(stderr, "Overwriting existing notes for object %s\n",
-                       sha1_to_hex(object));
-       }
+static int append_edit(int argc, const char **argv, const char *prefix)
+{
+       const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20], new_note[20];
+       const unsigned char *note;
+       char logmsg[100];
+       const char * const *usage;
+       struct msg_arg msg = { 0, 0, STRBUF_INIT };
+       struct option options[] = {
+               { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
+                       "note contents as a string", PARSE_OPT_NONEG,
+                       parse_msg_arg},
+               { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
+                       "note contents in a file", PARSE_OPT_NONEG,
+                       parse_file_arg},
+               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
+                       "reuse and edit specified note object", PARSE_OPT_NONEG,
+                       parse_reedit_arg},
+               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
+                       "reuse specified note object", PARSE_OPT_NONEG,
+                       parse_reuse_arg},
+               OPT_END()
+       };
+       int edit = !strcmp(argv[0], "edit");
+
+       usage = edit ? git_notes_edit_usage : git_notes_append_usage;
+       argc = parse_options(argc, argv, prefix, options, usage,
+                            PARSE_OPT_KEEP_ARGV0);
 
-       if (remove) {
-               msg.given = 1;
-               msg.use_editor = 0;
-               strbuf_reset(&(msg.buf));
+       if (2 < argc) {
+               error("too many parameters");
+               usage_with_options(usage, options);
        }
 
-       if (prune) {
-               hashclr(new_note);
-               prune_notes(t);
-               goto commit;
-       } else if (copy) {
-               const unsigned char *from_note = get_note(t, from_obj);
-               if (!from_note) {
-                       error("Missing notes on source object %s. Cannot copy.",
-                             sha1_to_hex(from_obj));
-                       retval = 1;
-                       goto end;
-               }
-               hashcpy(new_note, from_note);
-       } else
-               create_note(object, &msg, append, note, new_note);
+       if (msg.given && edit)
+               fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
+                       "for the 'edit' subcommand.\n"
+                       "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
+
+       object_ref = 1 < argc ? argv[1] : "HEAD";
+
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+       t = init_notes_check(argv[0]);
+       note = get_note(t, object);
+
+       create_note(object, &msg, !edit, note, new_note);
 
        if (is_null_sha1(new_note))
                remove_note(t, object);
        else
                add_note(t, object, new_note, combine_notes_overwrite);
 
-commit:
        snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
                 is_null_sha1(new_note) ? "removed" : "added", argv[0]);
        commit_notes(t, logmsg);
-
-end:
        free_notes(t);
        strbuf_release(&(msg.buf));
+       return 0;
+}
+
+static int show(int argc, const char **argv, const char *prefix)
+{
+       const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20];
+       const unsigned char *note;
+       int retval;
+       struct option options[] = {
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options, git_notes_show_usage,
+                            0);
+
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_show_usage, options);
+       }
+
+       object_ref = argc ? argv[0] : "HEAD";
+
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+       t = init_notes_check("show");
+       note = get_note(t, object);
+
+       if (!note)
+               retval = error("No note found for object %s.",
+                              sha1_to_hex(object));
+       else {
+               const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
+               retval = execv_git_cmd(show_args);
+       }
+       free_notes(t);
        return retval;
 }
+
+static int remove_cmd(int argc, const char **argv, const char *prefix)
+{
+       struct option options[] = {
+               OPT_END()
+       };
+       const char *object_ref;
+       struct notes_tree *t;
+       unsigned char object[20];
+
+       argc = parse_options(argc, argv, prefix, options,
+                            git_notes_remove_usage, 0);
+
+       if (1 < argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_remove_usage, options);
+       }
+
+       object_ref = argc ? argv[0] : "HEAD";
+
+       if (get_sha1(object_ref, object))
+               die("Failed to resolve '%s' as a valid ref.", object_ref);
+
+       t = init_notes_check("remove");
+
+       fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object));
+       remove_note(t, object);
+
+       commit_notes(t, "Notes removed by 'git notes remove'");
+       free_notes(t);
+       return 0;
+}
+
+static int prune(int argc, const char **argv, const char *prefix)
+{
+       struct notes_tree *t;
+       struct option options[] = {
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage,
+                            0);
+
+       if (argc) {
+               error("too many parameters");
+               usage_with_options(git_notes_prune_usage, options);
+       }
+
+       t = init_notes_check("prune");
+
+       prune_notes(t);
+       commit_notes(t, "Notes removed by 'git notes prune'");
+       free_notes(t);
+       return 0;
+}
+
+int cmd_notes(int argc, const char **argv, const char *prefix)
+{
+       int result;
+       const char *override_notes_ref = NULL;
+       struct option options[] = {
+               OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
+                          "use notes from <notes_ref>"),
+               OPT_END()
+       };
+
+       git_config(git_default_config, NULL);
+       argc = parse_options(argc, argv, prefix, options, git_notes_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (override_notes_ref) {
+               struct strbuf sb = STRBUF_INIT;
+               if (!prefixcmp(override_notes_ref, "refs/notes/"))
+                       /* we're happy */;
+               else if (!prefixcmp(override_notes_ref, "notes/"))
+                       strbuf_addstr(&sb, "refs/");
+               else
+                       strbuf_addstr(&sb, "refs/notes/");
+               strbuf_addstr(&sb, override_notes_ref);
+               setenv("GIT_NOTES_REF", sb.buf, 1);
+               strbuf_release(&sb);
+       }
+
+       if (argc < 1 || !strcmp(argv[0], "list"))
+               result = list(argc, argv, prefix);
+       else if (!strcmp(argv[0], "add"))
+               result = add(argc, argv, prefix);
+       else if (!strcmp(argv[0], "copy"))
+               result = copy(argc, argv, prefix);
+       else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit"))
+               result = append_edit(argc, argv, prefix);
+       else if (!strcmp(argv[0], "show"))
+               result = show(argc, argv, prefix);
+       else if (!strcmp(argv[0], "remove"))
+               result = remove_cmd(argc, argv, prefix);
+       else if (!strcmp(argv[0], "prune"))
+               result = prune(argc, argv, prefix);
+       else {
+               result = error("Unknown subcommand: %s", argv[0]);
+               usage_with_options(git_notes_usage, options);
+       }
+
+       return result ? 1 : 0;
+}
index 9780258..214d7ef 100644 (file)
@@ -18,8 +18,8 @@
 #include "refs.h"
 
 #ifndef NO_PTHREADS
-#include "thread-utils.h"
 #include <pthread.h>
+#include "thread-utils.h"
 #endif
 
 static const char pack_usage[] =
@@ -1522,6 +1522,13 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
 
 #ifndef NO_PTHREADS
 
+static void try_to_free_from_threads(size_t size)
+{
+       read_lock();
+       release_pack_memory(size, -1);
+       read_unlock();
+}
+
 /*
  * The main thread waits on the condition that (at least) one of the workers
  * has stopped working (which is indicated in the .working member of
@@ -1552,14 +1559,16 @@ static pthread_cond_t progress_cond;
  */
 static void init_threaded_search(void)
 {
-       pthread_mutex_init(&read_mutex, NULL);
+       init_recursive_mutex(&read_mutex);
        pthread_mutex_init(&cache_mutex, NULL);
        pthread_mutex_init(&progress_mutex, NULL);
        pthread_cond_init(&progress_cond, NULL);
+       set_try_to_free_routine(try_to_free_from_threads);
 }
 
 static void cleanup_threaded_search(void)
 {
+       set_try_to_free_routine(NULL);
        pthread_cond_destroy(&progress_cond);
        pthread_mutex_destroy(&read_mutex);
        pthread_mutex_destroy(&cache_mutex);
index 62957ed..f4358b9 100644 (file)
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-       "git push [<options>] [<repository> <refspec>...]",
+       "git push [<options>] [<repository> [<refspec>...]]",
        NULL,
 };
 
index 64e45bd..bd7880d 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 static const char reflog_expire_usage[] =
-"git reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
 static const char reflog_delete_usage[] =
 "git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
 
index 34f9ace..0048f9e 100644 (file)
@@ -89,7 +89,7 @@ static int diff_two(const char *file1, const char *label1,
        printf("--- a/%s\n+++ b/%s\n", label1, label2);
        fflush(stdout);
        memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = 0;
        memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
        ecb.outf = outf;
index 2c3a69a..1283068 100644 (file)
@@ -23,7 +23,8 @@
 
 static const char * const git_reset_usage[] = {
        "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]",
-       "git reset [--mixed] <commit> [--] <paths>...",
+       "git reset [-q] <commit> [--] <paths>...",
+       "git reset --patch [<commit>] [--] [<paths>...]",
        NULL
 };
 
index 5679170..51ceb19 100644 (file)
@@ -133,9 +133,12 @@ static void show_commit(struct commit *commit, void *data)
                                 */
                                if (graph_show_remainder(revs->graph))
                                        putchar('\n');
+                               if (revs->commit_format == CMIT_FMT_ONELINE)
+                                       putchar('\n');
                        }
                } else {
-                       if (buf.len)
+                       if (revs->commit_format != CMIT_FMT_USERFORMAT ||
+                           buf.len)
                                printf("%s%c", buf.buf, info->hdr_termination);
                }
                strbuf_release(&buf);
@@ -313,7 +316,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 
        git_config(git_default_config, NULL);
        init_revisions(&revs, prefix);
-       revs.abbrev = 0;
+       revs.abbrev = DEFAULT_ABBREV;
        revs.commit_format = CMIT_FMT_UNSPECIFIED;
        argc = setup_revisions(argc, argv, &revs, NULL);
 
index eff5268..7d68ef7 100644 (file)
@@ -13,6 +13,7 @@
 #include "revision.h"
 #include "rerere.h"
 #include "merge-recursive.h"
+#include "refs.h"
 
 /*
  * This implements the builtins revert and cherry-pick.
@@ -35,7 +36,7 @@ static const char * const cherry_pick_usage[] = {
        NULL
 };
 
-static int edit, no_replay, no_commit, mainline, signoff;
+static int edit, no_replay, no_commit, mainline, signoff, allow_ff;
 static enum { REVERT, CHERRY_PICK } action;
 static struct commit *commit;
 static const char *commit_name;
@@ -45,6 +46,8 @@ static const char *me;
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
+static char *get_encoding(const char *message);
+
 static void parse_args(int argc, const char **argv)
 {
        const char * const * usage_str =
@@ -60,8 +63,19 @@ static void parse_args(int argc, const char **argv)
                OPT_INTEGER('m', "mainline", &mainline, "parent number"),
                OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
                OPT_END(),
+               OPT_END(),
+               OPT_END(),
        };
 
+       if (action == CHERRY_PICK) {
+               struct option cp_extra[] = {
+                       OPT_BOOLEAN(0, "ff", &allow_ff, "allow fast-forward"),
+                       OPT_END(),
+               };
+               if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
+                       die("program error");
+       }
+
        if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1)
                usage_with_options(usage_str, options);
 
@@ -73,33 +87,69 @@ static void parse_args(int argc, const char **argv)
                exit(1);
 }
 
-static char *get_oneline(const char *message)
+struct commit_message {
+       char *parent_label;
+       const char *label;
+       const char *subject;
+       char *reencoded_message;
+       const char *message;
+};
+
+static int get_message(const char *raw_message, struct commit_message *out)
 {
-       char *result;
-       const char *p = message, *abbrev, *eol;
+       const char *encoding;
+       const char *p, *abbrev, *eol;
+       char *q;
        int abbrev_len, oneline_len;
 
-       if (!p)
-               die ("Could not read commit message of %s",
-                               sha1_to_hex(commit->object.sha1));
+       if (!raw_message)
+               return -1;
+       encoding = get_encoding(raw_message);
+       if (!encoding)
+               encoding = "UTF-8";
+       if (!git_commit_encoding)
+               git_commit_encoding = "UTF-8";
+
+       out->reencoded_message = NULL;
+       out->message = raw_message;
+       if (strcmp(encoding, git_commit_encoding))
+               out->reencoded_message = reencode_string(raw_message,
+                                       git_commit_encoding, encoding);
+       if (out->reencoded_message)
+               out->message = out->reencoded_message;
+
+       abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
+       abbrev_len = strlen(abbrev);
+
+       /* Find beginning and end of commit subject. */
+       p = out->message;
        while (*p && (*p != '\n' || p[1] != '\n'))
                p++;
-
        if (*p) {
                p += 2;
                for (eol = p + 1; *eol && *eol != '\n'; eol++)
                        ; /* do nothing */
        } else
                eol = p;
-       abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
-       abbrev_len = strlen(abbrev);
        oneline_len = eol - p;
-       result = xmalloc(abbrev_len + 5 + oneline_len);
-       memcpy(result, abbrev, abbrev_len);
-       memcpy(result + abbrev_len, "... ", 4);
-       memcpy(result + abbrev_len + 4, p, oneline_len);
-       result[abbrev_len + 4 + oneline_len] = '\0';
-       return result;
+
+       out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
+                             strlen("... ") + oneline_len + 1);
+       q = out->parent_label;
+       q = mempcpy(q, "parent of ", strlen("parent of "));
+       out->label = q;
+       q = mempcpy(q, abbrev, abbrev_len);
+       q = mempcpy(q, "... ", strlen("... "));
+       out->subject = q;
+       q = mempcpy(q, p, oneline_len);
+       *q = '\0';
+       return 0;
+}
+
+static void free_message(struct commit_message *msg)
+{
+       free(msg->parent_label);
+       free(msg->reencoded_message);
 }
 
 static char *get_encoding(const char *message)
@@ -244,14 +294,25 @@ static NORETURN void die_dirty_index(const char *me)
        }
 }
 
+static int fast_forward_to(const unsigned char *to, const unsigned char *from)
+{
+       struct ref_lock *ref_lock;
+
+       read_cache();
+       if (checkout_fast_forward(from, to))
+               exit(1); /* the callee should have complained already */
+       ref_lock = lock_any_ref_for_update("HEAD", from, 0);
+       return write_ref_sha1(ref_lock, to, "cherry-pick");
+}
+
 static int revert_or_cherry_pick(int argc, const char **argv)
 {
        unsigned char head[20];
        struct commit *base, *next, *parent;
+       const char *base_label, *next_label;
        int i, index_fd, clean;
-       char *oneline, *reencoded_message = NULL;
-       const char *message, *encoding;
-       char *defmsg = git_pathdup("MERGE_MSG");
+       struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
+       char *defmsg = NULL;
        struct merge_options o;
        struct tree *result, *next_tree, *base_tree, *head_tree;
        static struct lock_file index_lock;
@@ -265,6 +326,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        if (action == REVERT && !no_replay)
                die("revert is incompatible with replay");
 
+       if (allow_ff) {
+               if (signoff)
+                       die("cherry-pick --ff cannot be used with --signoff");
+               if (no_commit)
+                       die("cherry-pick --ff cannot be used with --no-commit");
+               if (no_replay)
+                       die("cherry-pick --ff cannot be used with -x");
+               if (edit)
+                       die("cherry-pick --ff cannot be used with --edit");
+       }
+
        if (read_cache() < 0)
                die("git %s: failed to read the index", me);
        if (no_commit) {
@@ -284,8 +356,6 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        }
        discard_cache();
 
-       index_fd = hold_locked_index(&index_lock, 1);
-
        if (!commit->parents) {
                if (action == REVERT)
                        die ("Cannot revert a root commit");
@@ -314,14 +384,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        else
                parent = commit->parents->item;
 
-       if (!(message = commit->buffer))
-               die ("Cannot get commit message for %s",
-                               sha1_to_hex(commit->object.sha1));
+       if (allow_ff && !hashcmp(parent->object.sha1, head))
+               return fast_forward_to(commit->object.sha1, head);
 
        if (parent && parse_commit(parent) < 0)
                die("%s: cannot parse parent commit %s",
                    me, sha1_to_hex(parent->object.sha1));
 
+       if (get_message(commit->buffer, &msg) != 0)
+               die("Cannot get commit message for %s",
+                               sha1_to_hex(commit->object.sha1));
+
        /*
         * "commit" is an existing commit.  We would want to apply
         * the difference it introduces since its first parent "prev"
@@ -329,27 +402,19 @@ static int revert_or_cherry_pick(int argc, const char **argv)
         * reverse of it if we are revert.
         */
 
+       defmsg = git_pathdup("MERGE_MSG");
        msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
                                           LOCK_DIE_ON_ERROR);
 
-       encoding = get_encoding(message);
-       if (!encoding)
-               encoding = "UTF-8";
-       if (!git_commit_encoding)
-               git_commit_encoding = "UTF-8";
-       if ((reencoded_message = reencode_string(message,
-                                       git_commit_encoding, encoding)))
-               message = reencoded_message;
-
-       oneline = get_oneline(message);
+       index_fd = hold_locked_index(&index_lock, 1);
 
        if (action == REVERT) {
-               char *oneline_body = strchr(oneline, ' ');
-
                base = commit;
+               base_label = msg.label;
                next = parent;
+               next_label = msg.parent_label;
                add_to_msg("Revert \"");
-               add_to_msg(oneline_body + 1);
+               add_to_msg(msg.subject);
                add_to_msg("\"\n\nThis reverts commit ");
                add_to_msg(sha1_to_hex(commit->object.sha1));
 
@@ -360,9 +425,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
                add_to_msg(".\n");
        } else {
                base = parent;
+               base_label = msg.parent_label;
                next = commit;
-               set_author_ident_env(message);
-               add_message_to_msg(message);
+               next_label = msg.label;
+               set_author_ident_env(msg.message);
+               add_message_to_msg(msg.message);
                if (no_replay) {
                        add_to_msg("(cherry picked from commit ");
                        add_to_msg(sha1_to_hex(commit->object.sha1));
@@ -372,8 +439,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
 
        read_cache();
        init_merge_options(&o);
+       o.ancestor = base ? base_label : "(empty tree)";
        o.branch1 = "HEAD";
-       o.branch2 = oneline;
+       o.branch2 = next ? next_label : "(empty tree)";
 
        head_tree = parse_tree_indirect(head);
        next_tree = next ? next->tree : empty_tree();
@@ -437,7 +505,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
                args[i] = NULL;
                return execv_git_cmd(args);
        }
-       free(reencoded_message);
+       free_message(&msg);
        free(defmsg);
 
        return 0;
index 06320f5..5089502 100644 (file)
@@ -162,7 +162,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
                    sha1_to_hex(commit->object.sha1));
        if (log->user_format) {
                struct pretty_print_context ctx = {0};
-               ctx.abbrev = DEFAULT_ABBREV;
+               ctx.abbrev = log->abbrev;
                ctx.subject = "";
                ctx.after_subject = "";
                ctx.date_mode = DATE_NORMAL;
@@ -290,6 +290,7 @@ parse_done:
        }
 
        log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
+       log.abbrev = rev.abbrev;
 
        /* assume HEAD if from a tty */
        if (!nongit && !rev.pending.nr && isatty(0))
index e20fcf3..e8719aa 100644 (file)
@@ -313,7 +313,8 @@ static void show_one_commit(struct commit *commit, int no_name)
                }
                else
                        printf("[%s] ",
-                              find_unique_abbrev(commit->object.sha1, 7));
+                              find_unique_abbrev(commit->object.sha1,
+                                                 DEFAULT_ABBREV));
        }
        puts(pretty_str);
        strbuf_release(&pretty);
index 4ef1c4f..d311491 100644 (file)
@@ -147,11 +147,11 @@ static int delete_tag(const char *name, const char *ref,
 static int verify_tag(const char *name, const char *ref,
                                const unsigned char *sha1)
 {
-       const char *argv_verify_tag[] = {"git-verify-tag",
+       const char *argv_verify_tag[] = {"verify-tag",
                                        "-v", "SHA1_HEX", NULL};
        argv_verify_tag[2] = sha1_to_hex(sha1);
 
-       if (run_command_v_opt(argv_verify_tag, 0))
+       if (run_command_v_opt(argv_verify_tag, RUN_GIT_CMD))
                return error("could not verify the tag '%s'", name);
        return 0;
 }
diff --git a/cache.h b/cache.h
index 2928107..0d101e4 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -701,7 +701,7 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *
        return read_sha1_file_repl(sha1, type, size, NULL);
 }
 extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
+extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
 extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 
@@ -905,7 +905,7 @@ struct extra_have_objects {
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
 extern int server_supports(const char *feature);
 
-extern struct packed_git *parse_pack_index(unsigned char *sha1);
+extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 
 extern void prepare_packed_git(void);
 extern void reprepare_packed_git(void);
@@ -916,6 +916,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
 
 extern void pack_report(void);
 extern int open_pack_index(struct packed_git *);
+extern void close_pack_index(struct packed_git *);
 extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
 extern void close_pack_windows(struct packed_git *);
 extern void unuse_pack(struct pack_window **);
@@ -1058,4 +1059,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix);
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 
+/* builtin/merge.c */
+int checkout_fast_forward(const unsigned char *from, const unsigned char *to);
+
 #endif /* CACHE_H */
index 6162691..655fa89 100644 (file)
@@ -204,24 +204,23 @@ static void consume_line(void *state_, char *line, unsigned long len)
 static void combine_diff(const unsigned char *parent, unsigned int mode,
                         mmfile_t *result_file,
                         struct sline *sline, unsigned int cnt, int n,
-                        int num_parent)
+                        int num_parent, int result_deleted)
 {
        unsigned int p_lno, lno;
        unsigned long nmask = (1UL << n);
        xpparam_t xpp;
        xdemitconf_t xecfg;
        mmfile_t parent_file;
-       xdemitcb_t ecb;
        struct combine_diff_state state;
        unsigned long sz;
 
-       if (!cnt)
+       if (result_deleted)
                return; /* result deleted */
 
        parent_file.ptr = grab_blob(parent, mode, &sz);
        parent_file.size = sz;
        memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = 0;
        memset(&xecfg, 0, sizeof(xecfg));
        memset(&state, 0, sizeof(state));
        state.nmask = nmask;
@@ -231,7 +230,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
        state.n = n;
 
        xdi_diff_outf(&parent_file, result_file, consume_line, &state,
-                     &xpp, &xecfg, &ecb);
+                     &xpp, &xecfg);
        free(parent_file.ptr);
 
        /* Assign line numbers for this parent.
@@ -517,7 +516,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)
 }
 
 static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
-                      int use_color)
+                      int use_color, int result_deleted)
 {
        unsigned long mark = (1UL<<num_parent);
        unsigned long no_pre_delete = (2UL<<num_parent);
@@ -530,7 +529,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
        const char *c_plain = diff_get_color(use_color, DIFF_PLAIN);
        const char *c_reset = diff_get_color(use_color, DIFF_RESET);
 
-       if (!cnt)
+       if (result_deleted)
                return; /* result deleted */
 
        while (1) {
@@ -687,6 +686,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
 {
        struct diff_options *opt = &rev->diffopt;
        unsigned long result_size, cnt, lno;
+       int result_deleted = 0;
        char *result, *cp;
        struct sline *sline; /* survived lines */
        int mode_differs = 0;
@@ -767,6 +767,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                }
                else {
                deleted_file:
+                       result_deleted = 1;
                        result_size = 0;
                        elem->mode = 0;
                        result = xcalloc(1, 1);
@@ -823,7 +824,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        combine_diff(elem->parent[i].sha1,
                                     elem->parent[i].mode,
                                     &result_file, sline,
-                                    cnt, i, num_parent);
+                                    cnt, i, num_parent, result_deleted);
                if (elem->parent[i].mode != elem->mode)
                        mode_differs = 1;
        }
@@ -889,7 +890,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        dump_quoted_path("+++ ", b_prefix, elem->path,
                                         c_meta, c_reset);
                dump_sline(sline, cnt, num_parent,
-                          DIFF_OPT_TST(opt, COLOR_DIFF));
+                          DIFF_OPT_TST(opt, COLOR_DIFF), result_deleted);
        }
        free(result);
 
index 3cf5166..26ec8c0 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -74,11 +74,16 @@ struct pretty_print_context
        struct reflog_walk_info *reflog_info;
 };
 
+struct userformat_want {
+       unsigned notes:1;
+};
+
 extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern char *reencode_commit_message(const struct commit *commit,
                                     const char **encoding_p);
 extern void get_commit_format(const char *arg, struct rev_info *);
+extern void userformat_find_requirements(const char *fmt, struct userformat_want *w);
 extern void format_commit_message(const struct commit *commit,
                                  const char *format, struct strbuf *sb,
                                  const struct pretty_print_context *context);
index f3b8c44..54756db 100644 (file)
@@ -17,6 +17,8 @@ static inline uint32_t default_swab32(uint32_t val)
                ((val & 0x000000ff) << 24));
 }
 
+#undef bswap32
+
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
 #define bswap32(x) ({ \
index c5bfb39..9a8e336 100644 (file)
@@ -140,6 +140,23 @@ int mingw_open (const char *filename, int oflags, ...)
        return fd;
 }
 
+#undef write
+ssize_t mingw_write(int fd, const void *buf, size_t count)
+{
+       /*
+        * While write() calls to a file on a local disk are translated
+        * into WriteFile() calls with a maximum size of 64KB on Windows
+        * XP and 256KB on Vista, no such cap is placed on writes to
+        * files over the network on Windows XP.  Unfortunately, there
+        * seems to be a limit of 32MB-28KB on X64 and 64MB-32KB on x86;
+        * bigger writes fail on Windows XP.
+        * So we cap to a nice 31MB here to avoid write failures over
+        * the net without changing the number of WriteFile() calls in
+        * the local case.
+        */
+       return write(fd, buf, min(count, 31 * 1024 * 1024));
+}
+
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
@@ -275,8 +292,17 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
        int fh, rc;
 
        /* must have write permission */
-       if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0)
-               return -1;
+       DWORD attrs = GetFileAttributes(file_name);
+       if (attrs != INVALID_FILE_ATTRIBUTES &&
+           (attrs & FILE_ATTRIBUTE_READONLY)) {
+               /* ignore errors here; open() will report them */
+               SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
+       }
+
+       if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) {
+               rc = -1;
+               goto revert_attrs;
+       }
 
        time_t_to_filetime(times->modtime, &mft);
        time_t_to_filetime(times->actime, &aft);
@@ -286,6 +312,13 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
        } else
                rc = 0;
        close(fh);
+
+revert_attrs:
+       if (attrs != INVALID_FILE_ATTRIBUTES &&
+           (attrs & FILE_ATTRIBUTE_READONLY)) {
+               /* ignore errors again */
+               SetFileAttributes(file_name, attrs);
+       }
        return rc;
 }
 
@@ -634,6 +667,7 @@ static int env_compare(const void *a, const void *b)
 }
 
 static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+                             const char *dir,
                              int prepend_cmd, int fhin, int fhout, int fherr)
 {
        STARTUPINFO si;
@@ -713,7 +747,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 
        memset(&pi, 0, sizeof(pi));
        ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-               env ? envblk.buf : NULL, NULL, &si, &pi);
+               env ? envblk.buf : NULL, dir, &si, &pi);
 
        if (env)
                strbuf_release(&envblk);
@@ -730,10 +764,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
 static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
                           int prepend_cmd)
 {
-       return mingw_spawnve_fd(cmd, argv, env, prepend_cmd, 0, 1, 2);
+       return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+                    const char *dir,
                     int fhin, int fhout, int fherr)
 {
        pid_t pid;
@@ -756,14 +791,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
                                pid = -1;
                        }
                        else {
-                               pid = mingw_spawnve_fd(iprog, argv, env, 1,
+                               pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
                                                       fhin, fhout, fherr);
                                free(iprog);
                        }
                        argv[0] = argv0;
                }
                else
-                       pid = mingw_spawnve_fd(prog, argv, env, 0,
+                       pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
                                               fhin, fhout, fherr);
                free(prog);
        }
index e81e752..0e3e743 100644 (file)
@@ -170,6 +170,9 @@ int link(const char *oldpath, const char *newpath);
 int mingw_open (const char *filename, int oflags, ...);
 #define open mingw_open
 
+ssize_t mingw_write(int fd, const void *buf, size_t count);
+#define write mingw_write
+
 FILE *mingw_fopen (const char *filename, const char *otype);
 #define fopen mingw_fopen
 
@@ -229,6 +232,7 @@ int mingw_utime(const char *file_name, const struct utimbuf *times);
 #define utime mingw_utime
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+                    const char *dir,
                     int fhin, int fhout, int fherr);
 void mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
diff --git a/compat/vcbuild/include/termios.h b/compat/vcbuild/include/termios.h
new file mode 100644 (file)
index 0000000..0d8552a
--- /dev/null
@@ -0,0 +1 @@
+/* Intentionally empty file to support building git with MSVC */
index c72f100..a45f8d6 100644 (file)
  */
 #define pthread_mutex_t CRITICAL_SECTION
 
-#define pthread_mutex_init(a,b) InitializeCriticalSection((a))
+#define pthread_mutex_init(a,b) (InitializeCriticalSection((a)), 0)
 #define pthread_mutex_destroy(a) DeleteCriticalSection((a))
 #define pthread_mutex_lock EnterCriticalSection
 #define pthread_mutex_unlock LeaveCriticalSection
 
+typedef int pthread_mutexattr_t;
+#define pthread_mutexattr_init(a) (*(a) = 0)
+#define pthread_mutexattr_destroy(a) do {} while (0)
+#define pthread_mutexattr_settype(a, t) 0
+#define PTHREAD_MUTEX_RECURSIVE 0
+
 /*
  * Implement simple condition variable for Windows threads, based on ACE
  * implementation.
index 1c5a149..b58aa69 100644 (file)
@@ -4,19 +4,19 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
 {
        HANDLE hmap;
        void *temp;
-       size_t len;
+       off_t len;
        struct stat st;
        uint64_t o = offset;
        uint32_t l = o & 0xFFFFFFFF;
        uint32_t h = (o >> 32) & 0xFFFFFFFF;
 
        if (!fstat(fd, &st))
-               len = xsize_t(st.st_size);
+               len = st.st_size;
        else
                die("mmap: could not determine filesize");
 
        if ((length + offset) > len)
-               length = len - offset;
+               length = xsize_t(len - offset);
 
        if (!(flags & MAP_PRIVATE))
                die("Invalid usage of mmap when built with USE_WIN32_MMAP");
index 6008ac9..0d4b64d 100644 (file)
@@ -31,6 +31,7 @@ NO_OPENSSL=@NO_OPENSSL@
 NO_CURL=@NO_CURL@
 NO_EXPAT=@NO_EXPAT@
 NO_LIBGEN_H=@NO_LIBGEN_H@
+HAVE_PATHS_H=@HAVE_PATHS_H@
 NEEDS_LIBICONV=@NEEDS_LIBICONV@
 NEEDS_SOCKET=@NEEDS_SOCKET@
 NEEDS_RESOLV=@NEEDS_RESOLV@
index 914ae57..71038fc 100644 (file)
@@ -179,6 +179,26 @@ fi],
    AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads.])
 ])
 
+# Define option to enable JavaScript minification
+AC_ARG_ENABLE([jsmin],
+[AS_HELP_STRING([--enable-jsmin=PATH],
+  [PATH is the name of a JavaScript minifier or the absolute path to one.])],
+[
+  JSMIN=$enableval;
+  AC_MSG_NOTICE([Setting JSMIN to '$JSMIN' to enable JavaScript minifying])
+  GIT_CONF_APPEND_LINE(JSMIN=$enableval);
+])
+
+# Define option to enable CSS minification
+AC_ARG_ENABLE([cssmin],
+[AS_HELP_STRING([--enable-cssmin=PATH],
+  [PATH is the name of a CSS minifier or the absolute path to one.])],
+[
+  CSSMIN=$enableval;
+  AC_MSG_NOTICE([Setting CSSMIN to '$CSSMIN' to enable CSS minifying])
+  GIT_CONF_APPEND_LINE(CSSMIN=$enableval);
+])
+
 ## Site configuration (override autodetection)
 ## --with-PACKAGE[=ARG] and --without-PACKAGE
 AC_MSG_NOTICE([CHECKS for site configuration])
@@ -704,6 +724,12 @@ AC_CHECK_HEADER([libgen.h],
 [NO_LIBGEN_H=YesPlease])
 AC_SUBST(NO_LIBGEN_H)
 #
+# Define HAVE_PATHS_H if you have paths.h.
+AC_CHECK_HEADER([paths.h],
+[HAVE_PATHS_H=YesPlease],
+[HAVE_PATHS_H=])
+AC_SUBST(HAVE_PATHS_H)
+#
 # Define NO_STRCASESTR if you don't have strcasestr.
 GIT_CHECK_FUNC(strcasestr,
 [NO_STRCASESTR=],
diff --git a/contrib/ciabot/README b/contrib/ciabot/README
new file mode 100644 (file)
index 0000000..3b916ac
--- /dev/null
@@ -0,0 +1,12 @@
+These are hook scripts for the CIA notification service at <http://cia.vc/>
+
+They are maintained by Eric S. Raymond <esr@thyrsus.com>.  There is an
+upstream resource page for them at <http://www.catb.org/esr/ciabot/>,
+but they are unlikely to change rapidly.
+
+You probably want the Python version; it's faster, more capable, and
+better documented.  The shell version is maintained only as a fallback
+for use on hosting sites that don't permit Python hook scripts.
+
+You will find installation instructions for each script in its comment
+header.
diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py
new file mode 100755 (executable)
index 0000000..d0627e0
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
+# Distributed under BSD terms.
+#
+# This script contains porcelain and porcelain byproducts.
+# It's Python because the Python standard libraries avoid portability/security
+# issues raised by callouts in the ancestral Perl and sh scripts.  It should
+# be compatible back to Python 2.1.5
+#
+# usage: ciabot.py [-V] [-n] [-p projectname]  [refname [commits...]]
+#
+# This script is meant to be run either in a post-commit hook or in an
+# update hook.  If there's nothing unusual about your hosting setup,
+# you can specify the project name with a -p option and avoid having
+# to modify this script.  Try it with -n to see the notification mail
+# dumped to stdout and verify that it looks sane. With -V it dumps its
+# version and exits.
+#
+# In post-commit, run it without arguments (other than possibly a -p
+# option). It will query for current HEAD and the latest commit ID to
+# get the information it needs.
+#
+# In update, call it with a refname followed by a list of commits:
+# You want to reverse the order git rev-list emits becxause it lists
+# from most recent to oldest.
+#
+# /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
+#
+# Note: this script uses mail, not XML-RPC, in order to avoid stalling
+# until timeout when the CIA XML-RPC server is down.
+#
+
+#
+# The project as known to CIA. You will either want to change this
+# or invoke the script with a -p option to set it.
+#
+project=None
+
+#
+# You may not need to change these:
+#
+import os, sys, commands, socket, urllib
+
+# Name of the repository.
+# You can hardwire this to make the script faster.
+repo = os.path.basename(os.getcwd())
+
+# Fully-qualified domain name of this host.
+# You can hardwire this to make the script faster.
+host = socket.getfqdn()
+
+# Changeset URL prefix for your repo: when the commit ID is appended
+# to this, it should point at a CGI that will display the commit
+# through gitweb or something similar. The defaults will probably
+# work if you have a typical gitweb/cgit setup.
+#
+#urlprefix="http://%(host)s/cgi-bin/gitweb.cgi?p=%(repo)s;a=commit;h="
+urlprefix="http://%(host)s/cgi-bin/cgit.cgi/%(repo)s/commit/?id="
+
+# The service used to turn your gitwebbish URL into a tinyurl so it
+# will take up less space on the IRC notification line.
+tinyifier = "http://tinyurl.com/api-create.php?url="
+
+# The template used to generate the XML messages to CIA.  You can make
+# visible changes to the IRC-bot notification lines by hacking this.
+# The default will produce a notfication line that looks like this:
+#
+# ${project}: ${author} ${repo}:${branch} * ${rev} ${files}: ${logmsg} ${url}
+#
+# By omitting $files you can collapse the files part to a single slash.
+xml = '''\
+<message>
+  <generator>
+    <name>CIA Python client for Git</name>
+    <version>%(gitver)s</version>
+    <url>%(generator)s</url>
+  </generator>
+  <source>
+    <project>%(project)s</project>
+    <branch>%(repo)s:%(branch)s</branch>
+  </source>
+  <timestamp>%(ts)s</timestamp>
+  <body>
+    <commit>
+      <author>%(author)s</author>
+      <revision>%(rev)s</revision>
+      <files>
+        %(files)s
+      </files>
+      <log>%(logmsg)s %(url)s</log>
+      <url>%(url)s</url>
+    </commit>
+  </body>
+</message>
+'''
+
+#
+# No user-serviceable parts below this line:
+#
+
+# Addresses for the e-mail. The from address is a dummy, since CIA
+# will never reply to this mail.
+fromaddr = "CIABOT-NOREPLY@" + host
+toaddr = "cia@cia.navi.cx"
+
+# Identify the generator script.
+# Should only change when the script itself gets a new home and maintainer.
+generator="http://www.catb.org/~esr/ciabot.py"
+
+def do(command):
+    return commands.getstatusoutput(command)[1]
+
+def report(refname, merged):
+    "Generate a commit notification to be reported to CIA"
+
+    # Try to tinyfy a reference to a web view for this commit.
+    try:
+        url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
+    except:
+        url = urlprefix + merged
+
+    branch = os.path.basename(refname)
+
+    # Compute a shortnane for the revision
+    rev = do("git describe ${merged} 2>/dev/null") or merged[:12]
+
+    # Extract the neta-information for the commit
+    rawcommit = do("git cat-file commit " + merged)
+    files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")
+    inheader = True
+    headers = {}
+    logmsg = ""
+    for line in rawcommit.split("\n"):
+        if inheader:
+            if line:
+                fields = line.split()
+                headers[fields[0]] = " ".join(fields[1:])
+            else:
+                inheader = False
+        else:
+            logmsg = line
+            break
+    (author, ts) = headers["author"].split(">")
+
+    # This discards the part of the authors addrsss after @.
+    # Might be bnicece to ship the full email address, if not
+    # for spammers' address harvesters - getting this wrong
+    # would make the freenode #commits channel into harvester heaven.
+    author = author.replace("<", "").split("@")[0].split()[-1]
+
+    # This ignores the timezone.  Not clear what to do with it...
+    ts = ts.strip().split()[0]
+
+    context = locals()
+    context.update(globals())
+
+    out = xml % context
+
+    message = '''\
+Message-ID: <%(merged)s.%(author)s@%(project)s>
+From: %(fromaddr)s
+To: %(toaddr)s
+Content-type: text/xml
+Subject: DeliverXML
+
+%(out)s''' % locals()
+
+    return message
+
+if __name__ == "__main__":
+    import getopt
+
+    try:
+        (options, arguments) = getopt.getopt(sys.argv[1:], "np:V")
+    except getopt.GetoptError, msg:
+        print "ciabot.py: " + str(msg)
+        raise SystemExit, 1
+
+    mailit = True
+    for (switch, val) in options:
+        if switch == '-p':
+            project = val
+        elif switch == '-n':
+            mailit = False
+        elif switch == '-V':
+            print "ciabot.py: version 3.2"
+            sys.exit(0)
+
+    # Cough and die if user has not specified a project
+    if not project:
+        sys.stderr.write("ciabot.py: no project specified, bailing out.\n")
+        sys.exit(1)
+
+    # We'll need the git version number.
+    gitver = do("git --version").split()[0]
+
+    urlprefix = urlprefix % globals()
+
+    # The script wants a reference to head followed by the list of
+    # commit ID to report about.
+    if len(arguments) == 0:
+        refname = do("git symbolic-ref HEAD 2>/dev/null")
+        merges = [do("git rev-parse HEAD")]
+    else:
+        refname = arguments[0]
+        merges = arguments[1:]
+
+    if mailit:
+        import smtplib
+        server = smtplib.SMTP('localhost')
+
+    for merged in merges:
+        message = report(refname, merged)
+        if mailit:
+            server.sendmail(fromaddr, [toaddr], message)
+        else:
+            print message
+
+    if mailit:
+        server.quit()
+
+#End
diff --git a/contrib/ciabot/ciabot.sh b/contrib/ciabot/ciabot.sh
new file mode 100755 (executable)
index 0000000..eb87bba
--- /dev/null
@@ -0,0 +1,192 @@
+#!/bin/sh
+# Distributed under the terms of the GNU General Public License v2
+# Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org>
+# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
+# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
+#
+# This is a version 3.x of ciabot.sh; use -V to find the exact
+# version.  Versions 1 and 2 were shipped in 2006 and 2008 and are not
+# version-stamped.  The version 2 maintainer has passed the baton.
+#
+# Note: This script should be considered obsolete.
+# There is a faster, better-documented rewrite in Python: find it as ciabot.py
+# Use this only if your hosting site forbids Python hooks.
+#
+# Originally based on Git ciabot.pl by Petr Baudis.
+# This script contains porcelain and porcelain byproducts.
+#
+# usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit]
+#
+# This script is meant to be run either in a post-commit hook or in an
+# update hook.  If there's nothing unusual about your hosting setup,
+# you can specify the project name with a -p option and avoid having
+# to modify this script.  Try it with -n first to see the notification
+# mail dumped to stdout and verify that it looks sane.  Use -V to dump
+# the version and exit.
+#
+# In post-commit, run it without arguments (other than possibly a -p
+# option). It will query for current HEAD and the latest commit ID to
+# get the information it needs.
+#
+# In update, you have to call it once per merged commit:
+#
+#       refname=$1
+#       oldhead=$2
+#       newhead=$3
+#       for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
+#               /path/to/ciabot.bash ${refname} ${merged}
+#       done
+#
+# The reason for the tac call ids that git rev-list emits commits from
+# most recent to least - better to ship notifactions from oldest to newest.
+#
+# Note: this script uses mail, not XML-RPC, in order to avoid stalling
+# until timeout when the CIA XML-RPC server is down.
+#
+
+#
+# The project as known to CIA. You will either want to change this
+# or set the project name with a -p option.
+#
+project=
+
+#
+# You may not need to change these:
+#
+
+# Name of the repository.
+# You can hardwire this to make the script faster.
+repo="`basename ${PWD}`"
+
+# Fully qualified domain name of the repo host.
+# You can hardwire this to make the script faster.
+host=`hostname --fqdn`
+
+# Changeset URL prefix for your repo: when the commit ID is appended
+# to this, it should point at a CGI that will display the commit
+# through gitweb or something similar. The defaults will probably
+# work if you have a typical gitweb/cgit setup.
+#urlprefix="http://${host}/cgi-bin/gitweb.cgi?p=${repo};a=commit;h="
+urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id="
+
+#
+# You probably will not need to change the following:
+#
+
+# Identify the script. Should change only when the script itself
+# gets a new home and maintainer.
+generator="http://www.catb.org/~esr/ciabot/ciabot.sh"
+
+# Addresses for the e-mail
+from="CIABOT-NOREPLY@${host}"
+to="cia@cia.navi.cx"
+
+# SMTP client to use - may need to edit the absolute pathname for your system
+sendmail="sendmail -t -f ${from}"
+
+#
+# No user-serviceable parts below this line:
+#
+
+# Should include all places sendmail is likely to lurk.
+PATH="$PATH:/usr/sbin/"
+
+mode=mailit
+while getopts pnV opt
+do
+    case $opt in
+       p) project=$2; shift ; shift ;;
+       n) mode=dumpit; shift ;;
+       V) echo "ciabot.sh: version 3.2"; exit 0; shift ;;
+    esac
+done
+
+# Cough and die if user has not specified a project
+if [ -z "$project" ]
+then
+    echo "ciabot.sh: no project specified, bailing out." >&2
+    exit 1
+fi
+
+if [ $# -eq 0 ] ; then
+       refname=$(git symbolic-ref HEAD 2>/dev/null)
+       merged=$(git rev-parse HEAD)
+else
+       refname=$1
+       merged=$2
+fi
+
+# This tries to turn your gitwebbish URL into a tinyurl so it will take up
+# less space on the IRC notification line. Some repo sites (I'm looking at
+# you, berlios.de!) forbid wget calls for security reasons.  On these,
+# the code will fall back to the full un-tinyfied URL.
+longurl=${urlprefix}${merged}
+url=$(wget -O - -q http://tinyurl.com/api-create.php?url=${longurl} 2>/dev/null)
+if [ -z "$url" ]; then
+       url="${longurl}"
+fi
+
+refname=${refname##refs/heads/}
+
+gitver=$(git --version)
+gitver=${gitver##* }
+
+rev=$(git describe ${merged} 2>/dev/null)
+# ${merged:0:12} was the only bashism left in the 2008 version of this
+# script, according to checkbashisms.  Replace it with ${merged} here
+# because it was just a fallback anyway, and it's worth accepting a
+# longer fallback for faster execution and removing the bash
+# dependency.
+[ -z ${rev} ] && rev=${merged}
+
+# This discards the part of the author's address after @.
+# Might be nice to ship the full email address, if not
+# for spammers' address harvesters - getting this wrong
+# would make the freenode #commits channel into harvester heaven.
+rawcommit=$(git cat-file commit ${merged})
+author=$(echo "$rawcommit" | sed -n -e '/^author .*<\([^@]*\).*$/s--\1-p')
+logmessage=$(echo "$rawcommit" | sed -e '1,/^$/d' | head -n 1)
+logmessage=$(echo "$logmessage" | sed 's/\&/&amp\;/g; s/</&lt\;/g; s/>/&gt\;/g')
+ts=$(echo "$rawcommit" | sed -n -e '/^author .*> \([0-9]\+\).*$/s--\1-p')
+files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-')
+
+out="
+<message>
+  <generator>
+    <name>CIA Shell client for Git</name>
+    <version>${gitver}</version>
+    <url>${generator}</url>
+  </generator>
+  <source>
+    <project>${project}</project>
+    <branch>$repo:${refname}</branch>
+  </source>
+  <timestamp>${ts}</timestamp>
+  <body>
+    <commit>
+      <author>${author}</author>
+      <revision>${rev}</revision>
+      <files>
+       ${files}
+      </files>
+      <log>${logmessage} ${url}</log>
+      <url>${url}</url>
+    </commit>
+  </body>
+</message>"
+
+if [ "$mode" = "dumpit" ]
+then
+    sendmail=cat
+fi
+
+${sendmail} << EOM
+Message-ID: <${merged}.${author}@${project}>
+From: ${from}
+To: ${to}
+Content-type: text/xml
+Subject: DeliverXML
+${out}
+EOM
+
+# vim: set tw=70 :
index 733ac39..57245a8 100755 (executable)
@@ -627,10 +627,19 @@ __git_aliased_command ()
        local word cmdline=$(git --git-dir="$(__gitdir)" \
                config --get "alias.$1")
        for word in $cmdline; do
-               if [ "${word##-*}" ]; then
-                       echo $word
+               case "$word" in
+               \!gitk|gitk)
+                       echo "gitk"
                        return
-               fi
+                       ;;
+               \!*)    : shell command alias ;;
+               -*)     : option ;;
+               *=*)    : setting env ;;
+               git)    : git itself ;;
+               *)
+                       echo "$word"
+                       return
+               esac
        done
 }
 
@@ -788,6 +797,7 @@ _git_branch ()
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
                        --track --no-track --contains --merged --no-merged
+                       --set-upstream
                        "
                ;;
        *)
@@ -1084,6 +1094,11 @@ _git_gc ()
        COMPREPLY=()
 }
 
+_git_gitk ()
+{
+       _gitk
+}
+
 _git_grep ()
 {
        __git_has_doubledash && return
@@ -1436,6 +1451,11 @@ _git_send_email ()
        COMPREPLY=()
 }
 
+_git_stage ()
+{
+       _git_add
+}
+
 __git_config_get_set_variables ()
 {
        local prevword word config_file= c=$COMP_CWORD
@@ -2167,6 +2187,11 @@ _git_tag ()
        esac
 }
 
+_git_whatchanged ()
+{
+       _git_log
+}
+
 _git ()
 {
        local i c=1 command __git_dir
@@ -2203,64 +2228,14 @@ _git ()
                return
        fi
 
+       local completion_func="_git_${command//-/_}"
+       declare -F $completion_func >/dev/null && $completion_func && return
+
        local expansion=$(__git_aliased_command "$command")
-       [ "$expansion" ] && command="$expansion"
-
-       case "$command" in
-       am)          _git_am ;;
-       add)         _git_add ;;
-       apply)       _git_apply ;;
-       archive)     _git_archive ;;
-       bisect)      _git_bisect ;;
-       bundle)      _git_bundle ;;
-       branch)      _git_branch ;;
-       checkout)    _git_checkout ;;
-       cherry)      _git_cherry ;;
-       cherry-pick) _git_cherry_pick ;;
-       clean)       _git_clean ;;
-       clone)       _git_clone ;;
-       commit)      _git_commit ;;
-       config)      _git_config ;;
-       describe)    _git_describe ;;
-       diff)        _git_diff ;;
-       difftool)    _git_difftool ;;
-       fetch)       _git_fetch ;;
-       format-patch) _git_format_patch ;;
-       fsck)        _git_fsck ;;
-       gc)          _git_gc ;;
-       grep)        _git_grep ;;
-       help)        _git_help ;;
-       init)        _git_init ;;
-       log)         _git_log ;;
-       ls-files)    _git_ls_files ;;
-       ls-remote)   _git_ls_remote ;;
-       ls-tree)     _git_ls_tree ;;
-       merge)       _git_merge;;
-       mergetool)   _git_mergetool;;
-       merge-base)  _git_merge_base ;;
-       mv)          _git_mv ;;
-       name-rev)    _git_name_rev ;;
-       notes)       _git_notes ;;
-       pull)        _git_pull ;;
-       push)        _git_push ;;
-       rebase)      _git_rebase ;;
-       remote)      _git_remote ;;
-       replace)     _git_replace ;;
-       reset)       _git_reset ;;
-       revert)      _git_revert ;;
-       rm)          _git_rm ;;
-       send-email)  _git_send_email ;;
-       shortlog)    _git_shortlog ;;
-       show)        _git_show ;;
-       show-branch) _git_show_branch ;;
-       stash)       _git_stash ;;
-       stage)       _git_add ;;
-       submodule)   _git_submodule ;;
-       svn)         _git_svn ;;
-       tag)         _git_tag ;;
-       whatchanged) _git_log ;;
-       *)           COMPREPLY=() ;;
-       esac
+       if [ -n "$expansion" ]; then
+               completion_func="_git_${expansion//-/_}"
+               declare -F $completion_func >/dev/null && $completion_func
+       fi
 }
 
 _gitk ()
index 7051a83..82f5ed3 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 ## zip archive frontend for git-fast-import
 ##
index 854cd94..046cb2b 100755 (executable)
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#!/usr/bin/env python
 
 """ hg-to-git.py - A Mercurial to GIT converter
 
index 58a35c8..30ae63d 100755 (executable)
 # possible for the email to be from someone other than the person doing the
 # push.
 #
+# To help with debugging and use on pre-v1.5.1 git servers, this script will
+# also obey the interface of hooks/update, taking its arguments on the
+# command line.  Unfortunately, hooks/update is called once for each ref.
+# To avoid firing one email per ref, this script just prints its output to
+# the screen when used in this mode.  The output can then be redirected if
+# wanted.
+#
 # Config
 # ------
 # hooks.mailinglist
index 0f3d97b..b6e534b 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #
 # This tool is copyright (c) 2006, Sean Estabrooks.
 # It is released under the Gnu Public License, version 2.
index 7d9e1c0..a90ab10 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -590,14 +590,17 @@ static int execute(struct sockaddr *addr)
 static int addrcmp(const struct sockaddr_storage *s1,
     const struct sockaddr_storage *s2)
 {
-       if (s1->ss_family != s2->ss_family)
-               return s1->ss_family - s2->ss_family;
-       if (s1->ss_family == AF_INET)
+       const struct sockaddr *sa1 = (const struct sockaddr*) s1;
+       const struct sockaddr *sa2 = (const struct sockaddr*) s2;
+
+       if (sa1->sa_family != sa2->sa_family)
+               return sa1->sa_family - sa2->sa_family;
+       if (sa1->sa_family == AF_INET)
                return memcmp(&((struct sockaddr_in *)s1)->sin_addr,
                    &((struct sockaddr_in *)s2)->sin_addr,
                    sizeof(struct in_addr));
 #ifndef NO_IPV6
-       if (s1->ss_family == AF_INET6)
+       if (sa1->sa_family == AF_INET6)
                return memcmp(&((struct sockaddr_in6 *)s1)->sin6_addr,
                    &((struct sockaddr_in6 *)s2)->sin6_addr,
                    sizeof(struct in6_addr));
diff --git a/date.c b/date.c
index 002aa3c..6bae49c 100644 (file)
--- a/date.c
+++ b/date.c
@@ -229,6 +229,7 @@ static const struct {
 
        { "GMT",    0, 0, },    /* Greenwich Mean */
        { "UTC",    0, 0, },    /* Universal (Coordinated) */
+       { "Z",      0, 0, },    /* Zulu, alias for UTC */
 
        { "WET",    0, 0, },    /* Western European */
        { "BST",    0, 1, },    /* British Summer */
@@ -305,7 +306,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
 
        for (i = 0; i < ARRAY_SIZE(timezone_names); i++) {
                int match = match_string(date, timezone_names[i].name);
-               if (match >= 3) {
+               if (match >= 3 || match == strlen(timezone_names[i].name)) {
                        int off = timezone_names[i].offset;
 
                        /* This is bogus, but we like summer */
index aae8e7a..4cd9dac 100644 (file)
@@ -150,16 +150,14 @@ static int queue_diff(struct diff_options *o,
 
 static int path_outside_repo(const char *path)
 {
-       /*
-        * We have already done setup_git_directory_gently() so we
-        * know we are inside a git work tree already.
-        */
        const char *work_tree;
        size_t len;
 
        if (!is_absolute_path(path))
                return 0;
        work_tree = get_git_work_tree();
+       if (!work_tree)
+               return 1;
        len = strlen(work_tree);
        if (strncmp(path, work_tree, len) ||
            (path[len] != '\0' && path[len] != '/'))
diff --git a/diff.c b/diff.c
index f5d93e9..230c310 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -14,6 +14,7 @@
 #include "userdiff.h"
 #include "sigchain.h"
 #include "submodule.h"
+#include "ll-merge.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -550,6 +551,10 @@ static void emit_rewrite_diff(const char *name_a,
                emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
        if (lc_b)
                emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
+       if (textconv_one)
+               free((char *)data_one);
+       if (textconv_two)
+               free((char *)data_two);
 }
 
 struct diff_words_buffer {
@@ -695,7 +700,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
 {
        xpparam_t xpp;
        xdemitconf_t xecfg;
-       xdemitcb_t ecb;
        mmfile_t minus, plus;
 
        /* special case: only removal */
@@ -713,11 +717,11 @@ static void diff_words_show(struct diff_words_data *diff_words)
        memset(&xecfg, 0, sizeof(xecfg));
        diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex);
        diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex);
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = 0;
        /* as only the hunk header will be parsed, we need a 0-context */
        xecfg.ctxlen = 0;
        xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
-                     &xpp, &xecfg, &ecb);
+                     &xpp, &xecfg);
        free(minus.ptr);
        free(plus.ptr);
        if (diff_words->current_plus != diff_words->plus.text.ptr +
@@ -948,7 +952,7 @@ struct diffstat_t {
                unsigned is_unmerged:1;
                unsigned is_binary:1;
                unsigned is_renamed:1;
-               unsigned int added, deleted;
+               uintmax_t added, deleted;
        } **files;
 };
 
@@ -1040,7 +1044,7 @@ static void fill_print_name(struct diffstat_file *file)
 static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
        int i, len, add, del, adds = 0, dels = 0;
-       int max_change = 0, max_len = 0;
+       uintmax_t max_change = 0, max_len = 0;
        int total_files = data->nr;
        int width, name_width;
        const char *reset, *set, *add_c, *del_c;
@@ -1069,7 +1073,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
-               int change = file->added + file->deleted;
+               uintmax_t change = file->added + file->deleted;
                fill_print_name(file);
                len = strlen(file->print_name);
                if (max_len < len)
@@ -1097,8 +1101,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
        for (i = 0; i < data->nr; i++) {
                const char *prefix = "";
                char *name = data->files[i]->print_name;
-               int added = data->files[i]->added;
-               int deleted = data->files[i]->deleted;
+               uintmax_t added = data->files[i]->added;
+               uintmax_t deleted = data->files[i]->deleted;
                int name_len;
 
                /*
@@ -1119,9 +1123,11 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                if (data->files[i]->is_binary) {
                        show_name(options->file, prefix, name, len);
                        fprintf(options->file, "  Bin ");
-                       fprintf(options->file, "%s%d%s", del_c, deleted, reset);
+                       fprintf(options->file, "%s%"PRIuMAX"%s",
+                               del_c, deleted, reset);
                        fprintf(options->file, " -> ");
-                       fprintf(options->file, "%s%d%s", add_c, added, reset);
+                       fprintf(options->file, "%s%"PRIuMAX"%s",
+                               add_c, added, reset);
                        fprintf(options->file, " bytes");
                        fprintf(options->file, "\n");
                        continue;
@@ -1150,7 +1156,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                        del = scale_linear(del, width, max_change);
                }
                show_name(options->file, prefix, name, len);
-               fprintf(options->file, "%5d%s", added + deleted,
+               fprintf(options->file, "%5"PRIuMAX"%s", added + deleted,
                                added + deleted ? " " : "");
                show_graph(options->file, '+', add, add_c, reset);
                show_graph(options->file, '-', del, del_c, reset);
@@ -1200,7 +1206,8 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options)
                        fprintf(options->file, "-\t-\t");
                else
                        fprintf(options->file,
-                               "%d\t%d\t", file->added, file->deleted);
+                               "%"PRIuMAX"\t%"PRIuMAX"\t",
+                               file->added, file->deleted);
                if (options->line_termination) {
                        fill_print_name(file);
                        if (!file->is_renamed)
@@ -1370,37 +1377,32 @@ static void free_diffstat_info(struct diffstat_t *diffstat)
 struct checkdiff_t {
        const char *filename;
        int lineno;
+       int conflict_marker_size;
        struct diff_options *o;
        unsigned ws_rule;
        unsigned status;
 };
 
-static int is_conflict_marker(const char *line, unsigned long len)
+static int is_conflict_marker(const char *line, int marker_size, unsigned long len)
 {
        char firstchar;
        int cnt;
 
-       if (len < 8)
+       if (len < marker_size + 1)
                return 0;
        firstchar = line[0];
        switch (firstchar) {
-       case '=': case '>': case '<':
+       case '=': case '>': case '<': case '|':
                break;
        default:
                return 0;
        }
-       for (cnt = 1; cnt < 7; cnt++)
+       for (cnt = 1; cnt < marker_size; cnt++)
                if (line[cnt] != firstchar)
                        return 0;
-       /* line[0] thru line[6] are same as firstchar */
-       if (firstchar == '=') {
-               /* divider between ours and theirs? */
-               if (len != 8 || line[7] != '\n')
-                       return 0;
-       } else if (len < 8 || !isspace(line[7])) {
-               /* not divider before ours nor after theirs */
+       /* line[1] thru line[marker_size-1] are same as firstchar */
+       if (len < marker_size + 1 || !isspace(line[marker_size]))
                return 0;
-       }
        return 1;
 }
 
@@ -1408,6 +1410,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
 {
        struct checkdiff_t *data = priv;
        int color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF);
+       int marker_size = data->conflict_marker_size;
        const char *ws = diff_get_color(color_diff, DIFF_WHITESPACE);
        const char *reset = diff_get_color(color_diff, DIFF_RESET);
        const char *set = diff_get_color(color_diff, DIFF_FILE_NEW);
@@ -1416,7 +1419,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
        if (line[0] == '+') {
                unsigned bad;
                data->lineno++;
-               if (is_conflict_marker(line + 1, len - 1)) {
+               if (is_conflict_marker(line + 1, marker_size, len - 1)) {
                        data->status |= 1;
                        fprintf(data->o->file,
                                "%s:%d: leftover conflict marker\n",
@@ -1646,21 +1649,21 @@ static void builtin_diff(const char *name_a,
        if (lbl[0][0] == '/') {
                /* /dev/null */
                strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset);
-               if (xfrm_msg && xfrm_msg[0])
-                       strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+               if (xfrm_msg)
+                       strbuf_addstr(&header, xfrm_msg);
        }
        else if (lbl[1][0] == '/') {
                strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
-               if (xfrm_msg && xfrm_msg[0])
-                       strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+               if (xfrm_msg)
+                       strbuf_addstr(&header, xfrm_msg);
        }
        else {
                if (one->mode != two->mode) {
                        strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset);
                        strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset);
                }
-               if (xfrm_msg && xfrm_msg[0])
-                       strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+               if (xfrm_msg)
+                       strbuf_addstr(&header, xfrm_msg);
 
                /*
                 * we do not run diff between different kind
@@ -1704,7 +1707,6 @@ static void builtin_diff(const char *name_a,
                const char *diffopts = getenv("GIT_DIFF_OPTS");
                xpparam_t xpp;
                xdemitconf_t xecfg;
-               xdemitcb_t ecb;
                struct emit_callback ecbdata;
                const struct userdiff_funcname *pe;
 
@@ -1743,7 +1745,7 @@ static void builtin_diff(const char *name_a,
                        check_blank_at_eof(&mf1, &mf2, &ecbdata);
                ecbdata.file = o->file;
                ecbdata.header = header.len ? &header : NULL;
-               xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
+               xpp.flags = o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
@@ -1776,7 +1778,7 @@ static void builtin_diff(const char *name_a,
                        }
                }
                xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
-                             &xpp, &xecfg, &ecb);
+                             &xpp, &xecfg);
                if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
                        free_diff_words_data(&ecbdata);
                if (textconv_one)
@@ -1829,13 +1831,12 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
-               xdemitcb_t ecb;
 
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
-               xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
+               xpp.flags = o->xdl_opts;
                xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
-                             &xpp, &xecfg, &ecb);
+                             &xpp, &xecfg);
        }
 
  free_and_return:
@@ -1860,6 +1861,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        data.lineno = 0;
        data.o = o;
        data.ws_rule = whitespace_rule(attr_path);
+       data.conflict_marker_size = ll_merge_marker_size(attr_path);
 
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
@@ -1876,14 +1878,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
-               xdemitcb_t ecb;
 
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                xecfg.ctxlen = 1; /* at least one context line */
-               xpp.flags = XDF_NEED_MINIMAL;
+               xpp.flags = 0;
                xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
-                             &xpp, &xecfg, &ecb);
+                             &xpp, &xecfg);
 
                if (data.ws_rule & WS_BLANK_AT_EOF) {
                        struct emit_callback ecbdata;
@@ -2318,30 +2319,36 @@ static void fill_metainfo(struct strbuf *msg,
                          struct diff_filespec *one,
                          struct diff_filespec *two,
                          struct diff_options *o,
-                         struct diff_filepair *p)
+                         struct diff_filepair *p,
+                         int use_color)
 {
+       const char *set = diff_get_color(use_color, DIFF_METAINFO);
+       const char *reset = diff_get_color(use_color, DIFF_RESET);
+
        strbuf_init(msg, PATH_MAX * 2 + 300);
        switch (p->status) {
        case DIFF_STATUS_COPIED:
-               strbuf_addf(msg, "similarity index %d%%", similarity_index(p));
-               strbuf_addstr(msg, "\ncopy from ");
+               strbuf_addf(msg, "%ssimilarity index %d%%",
+                           set, similarity_index(p));
+               strbuf_addf(msg, "%s\n%scopy from ", reset, set);
                quote_c_style(name, msg, NULL, 0);
-               strbuf_addstr(msg, "\ncopy to ");
+               strbuf_addf(msg, "%s\n%scopy to ", reset, set);
                quote_c_style(other, msg, NULL, 0);
-               strbuf_addch(msg, '\n');
+               strbuf_addf(msg, "%s\n", reset);
                break;
        case DIFF_STATUS_RENAMED:
-               strbuf_addf(msg, "similarity index %d%%", similarity_index(p));
-               strbuf_addstr(msg, "\nrename from ");
+               strbuf_addf(msg, "%ssimilarity index %d%%",
+                           set, similarity_index(p));
+               strbuf_addf(msg, "%s\n%srename from ", reset, set);
                quote_c_style(name, msg, NULL, 0);
-               strbuf_addstr(msg, "\nrename to ");
+               strbuf_addf(msg, "%s\n%srename to ", reset, set);
                quote_c_style(other, msg, NULL, 0);
-               strbuf_addch(msg, '\n');
+               strbuf_addf(msg, "%s\n", reset);
                break;
        case DIFF_STATUS_MODIFIED:
                if (p->score) {
-                       strbuf_addf(msg, "dissimilarity index %d%%\n",
-                                   similarity_index(p));
+                       strbuf_addf(msg, "%sdissimilarity index %d%%%s\n",
+                                   set, similarity_index(p), reset);
                        break;
                }
                /* fallthru */
@@ -2358,15 +2365,13 @@ static void fill_metainfo(struct strbuf *msg,
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
                                abbrev = 40;
                }
-               strbuf_addf(msg, "index %.*s..%.*s",
+               strbuf_addf(msg, "%sindex %.*s..%.*s", set,
                            abbrev, sha1_to_hex(one->sha1),
                            abbrev, sha1_to_hex(two->sha1));
                if (one->mode == two->mode)
                        strbuf_addf(msg, " %06o", one->mode);
-               strbuf_addch(msg, '\n');
+               strbuf_addf(msg, "%s\n", reset);
        }
-       if (msg->len)
-               strbuf_setlen(msg, msg->len - 1);
 }
 
 static void run_diff_cmd(const char *pgm,
@@ -2382,11 +2387,6 @@ static void run_diff_cmd(const char *pgm,
        const char *xfrm_msg = NULL;
        int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
 
-       if (msg) {
-               fill_metainfo(msg, name, other, one, two, o, p);
-               xfrm_msg = msg->len ? msg->buf : NULL;
-       }
-
        if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
                pgm = NULL;
        else {
@@ -2395,6 +2395,16 @@ static void run_diff_cmd(const char *pgm,
                        pgm = drv->external;
        }
 
+       if (msg) {
+               /*
+                * don't use colors when the header is intended for an
+                * external diff driver
+                */
+               fill_metainfo(msg, name, other, one, two, o, p,
+                             DIFF_OPT_TST(o, COLOR_DIFF) && !pgm);
+               xfrm_msg = msg->len ? msg->buf : NULL;
+       }
+
        if (pgm) {
                run_external_diff(pgm, name, other, one, two, xfrm_msg,
                                  complete_rewrite);
@@ -3378,7 +3388,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
        for (i = 0; i < q->nr; i++) {
                xpparam_t xpp;
                xdemitconf_t xecfg;
-               xdemitcb_t ecb;
                mmfile_t mf1, mf2;
                struct diff_filepair *p = q->queue[i];
                int len1, len2;
@@ -3436,11 +3445,11 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
                                        len2, p->two->path);
                git_SHA1_Update(&ctx, buffer, len1);
 
-               xpp.flags = XDF_NEED_MINIMAL;
+               xpp.flags = 0;
                xecfg.ctxlen = 3;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
                xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
-                             &xpp, &xecfg, &ecb);
+                             &xpp, &xecfg);
        }
 
        git_SHA1_Final(sha1, &ctx);
@@ -3883,6 +3892,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        const char **arg = argv;
        struct child_process child;
        struct strbuf buf = STRBUF_INIT;
+       int err = 0;
 
        temp = prepare_temp_file(spec->path, spec);
        *arg++ = pgm;
@@ -3893,16 +3903,20 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        child.use_shell = 1;
        child.argv = argv;
        child.out = -1;
-       if (start_command(&child) != 0 ||
-           strbuf_read(&buf, child.out, 0) < 0 ||
-           finish_command(&child) != 0) {
-               close(child.out);
-               strbuf_release(&buf);
+       if (start_command(&child)) {
                remove_tempfile();
-               error("error running textconv command '%s'", pgm);
                return NULL;
        }
+
+       if (strbuf_read(&buf, child.out, 0) < 0)
+               err = error("error reading from textconv command '%s'", pgm);
        close(child.out);
+
+       if (finish_command(&child) || err) {
+               strbuf_release(&buf);
+               remove_tempfile();
+               return NULL;
+       }
        remove_tempfile();
 
        return strbuf_detach(&buf, outsize);
diff --git a/dir.c b/dir.c
index cb83332..5615f33 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -958,9 +958,14 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
        }
        if (*dir)
                return NULL;
-       if (*cwd == '/')
+       switch (*cwd) {
+       case '\0':
+               return cwd;
+       case '/':
                return cwd + 1;
-       return cwd;
+       default:
+               return NULL;
+       }
 }
 
 int is_inside_dir(const char *dir)
index b2c07c7..bf22570 100644 (file)
@@ -107,7 +107,7 @@ void setup_path(void)
        if (old_path)
                strbuf_addstr(&new_path, old_path);
        else
-               strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
+               strbuf_addstr(&new_path, _PATH_DEFPATH);
 
        setenv("PATH", new_path.buf, 1);
 
index 21f1330..27fc793 100755 (executable)
@@ -1111,9 +1111,9 @@ sub help_patch_cmd {
        print colored $help_color, <<EOF ;
 y - $verb this hunk$target
 n - do not $verb this hunk$target
-q - quit, do not $verb this hunk nor any of the remaining ones
-a - $verb this and all the remaining hunks in the file
-d - do not $verb this hunk nor any of the remaining hunks in the file
+q - quit; do not $verb this hunk nor any of the remaining ones
+a - $verb this hunk and all later hunks in the file
+d - do not $verb this hunk nor any of the later hunks in the file
 g - select a hunk to go to
 / - search for a hunk matching the given regex
 j - leave this hunk undecided, see next undecided hunk
index 1056075..87ffae2 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -740,7 +740,7 @@ do
                ;;
        esac
 
-       if test $apply_status = 1 && test "$threeway" = t
+       if test $apply_status != 0 && test "$threeway" = t
        then
                if (fall_back_3way)
                then
index 3ebf966..c0198dd 100644 (file)
@@ -55,7 +55,8 @@
 # else
 # define _XOPEN_SOURCE 500
 # endif
-#elif !defined(__APPLE__) && !defined(__FreeBSD__)  && !defined(__USLC__) && !defined(_M_UNIX) && !defined(sgi)
+#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
+      !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__)
 #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #endif
@@ -163,6 +164,13 @@ extern char *gitbasename(char *);
 #define PATH_SEP ':'
 #endif
 
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifndef _PATH_DEFPATH
+#define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin"
+#endif
+
 #ifndef STRIP_EXTENSION
 #define STRIP_EXTENSION ""
 #endif
@@ -331,6 +339,7 @@ extern int git_vsnprintf(char *str, size_t maxsize,
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
 #define HAVE_STRCHRNUL
+#define HAVE_MEMPCPY
 #endif
 #endif
 
@@ -344,8 +353,18 @@ static inline char *gitstrchrnul(const char *s, int c)
 }
 #endif
 
+#ifndef HAVE_MEMPCPY
+#define mempcpy gitmempcpy
+static inline void *gitmempcpy(void *dest, const void *src, size_t n)
+{
+       return (char *)memcpy(dest, src, n) + n;
+}
+#endif
+
 extern void release_pack_memory(size_t, int);
 
+extern void set_try_to_free_routine(void (*routine)(size_t));
+
 extern char *xstrdup(const char *str);
 extern void *xmalloc(size_t size);
 extern void *xmallocz(size_t size);
index d975d07..adc42de 100755 (executable)
@@ -78,11 +78,13 @@ sub generate_command
                        next;
                }
                if ($arg eq '-g' || $arg eq '--gui') {
-                       my $tool = Git::command_oneline('config',
-                                                       'diff.guitool');
-                       if (length($tool)) {
-                               $ENV{GIT_DIFF_TOOL} = $tool;
-                       }
+                       eval {
+                               my $tool = Git::command_oneline('config',
+                                                               'diff.guitool');
+                               if (length($tool)) {
+                                       $ENV{GIT_DIFF_TOOL} = $tool;
+                               }
+                       };
                        next;
                }
                if ($arg eq '-y' || $arg eq '--no-prompt') {
index 6a65f25..f608014 100755 (executable)
@@ -212,7 +212,7 @@ server.errorlog = "$fqgitdir/gitweb/error.log"
 # variable above and uncomment this
 #accesslog.filename = "$fqgitdir/gitweb/access.log"
 
-setenv.add-environment = ( "PATH" => "/usr/local/bin:/usr/bin:/bin" )
+setenv.add-environment = ( "PATH" => env.PATH )
 
 cgi.assign = ( ".cgi" => "" )
 
@@ -361,7 +361,7 @@ error_log   $fqgitdir/gitweb/error.log
 access_log     $fqgitdir/gitweb/access.log
 
 #cgi setup
-cgi_env                PATH=/usr/local/bin:/usr/bin:/bin,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH
+cgi_env                PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH
 cgi_interp     $PERL
 cgi_ext                cgi,pl
 
@@ -391,18 +391,20 @@ EOFGITWEB
 gitweb_css () {
        cat > "$1" <<\EOFGITWEB
 @@GITWEB_CSS@@
+
 EOFGITWEB
 }
 
 gitweb_js () {
        cat > "$1" <<\EOFGITWEB
 @@GITWEB_JS@@
+
 EOFGITWEB
 }
 
 gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi"
-gitweb_css "$GIT_DIR/gitweb/gitweb.css"
-gitweb_js  "$GIT_DIR/gitweb/gitweb.js"
+gitweb_css "$GIT_DIR/@@GITWEB_CSS_NAME@@"
+gitweb_js  "$GIT_DIR/@@GITWEB_JS_NAME@@"
 
 case "$httpd" in
 *lighttpd*)