Code

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

227 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 [new file with mode: 0644]
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/t6000lib.sh [deleted file]
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 7b3acb766491e2e002f293cf9dd50298d0d7d83a..dbf1b90c63573b08efc894ed8c1e02de58fd53e4 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 88bd01e16d91f002cf3ac405e2a923884058d724..a8091eb5dfa430bf1b0537da47a31e7cf88d8622 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 8a8a3954dc45723f7380b59dadbb7e412198d672..04f69cf64e5d989bac3cd1c235e6a7e657c6c103 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 750d40f34ad36680640d6efd98b59ba6dc7900be..9d89fedb36b4d6fa7c8a6a8487cc47b4ca542e3a 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 c686f8646b465860c8a096241797709366cc4dc1..eb53e0636e3c3bab06e88ce3371945f5602c5756 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 4833cac4b996e83e351b70d8f02a160d04e9a8e3..16e3c685762a311eda1bbc39adb8ab19e000ec97 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 06b2f827b414651bde25165b4f42dc4160892d7a..ae174c99dba1d398eef66f13ec15b257eabb7034 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 60e922e6eff888f83a92d3747579ef45d993528a..3070dddfe2870b235dced1cf53da22d33ca8fb40 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 9310b650d3ca6b6cb7d69814eb9b800e8c2c85cd..e0ba8cc07549af375c89496c57c016a41b8cc699 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 51cbeb7032865599317fd9d7d36a9c9e2f8cc0c5..74741a42f409a7af5c60584a0d3b7a0be851811c 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 903a690f10e3cdb7aea15a19332bf0e8bc87814e..1940256930d92c0679b95bb0cd41f24847828bd4 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 37c1810e3fc8424868333a22094107e99764fc37..a3a87fa7fd29973e15afb93382646ae6f89d0f61 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 78f4714da0c226b9523f60f247f60ab13119c7c7..d71607a85d03062c76f7d17d4fd8e8b4168a279d 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 64fb458b4533eeda9c583ac926025495b260cf9b..69eb86e4506411b0d8029f849fd4ebff47166d05 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 948ea26c5a2b3825e61d0c6495d03829669a7351..400fe7f956961ba0ddf09d2dcc6e539adec7ff74 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 52388206570238636d50ed360120d3464f630a94..277d9e141bf81bddb4ba661e43763b7774a1417d 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 6cafbe2ec191b2e2b35e7855c71837fa0f231785..57aba42e6654e3d32617c3c7b17d18e8dd85852b 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 fb184ba1863845797a5f296581ec74a1b31bef1a..d7f6a9cc3ee335c5437e27dd362ef47c8753ff43 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 e3d58cbac3f162cc01d8731485f220fd70fed17b..3ea5aad56c5e1cec7fc2ca01ba9b5ea6badebe2f 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 9c9618cead5ae73a754ce741dfd423a7bd2298ca..c2325ef90e336a37df42eb7f71f95e3581c83127 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 4e5113b837230c8f050cf4bbe10e8de4b3271bd0..de63ef0745a82136eeee6a2f0993984f2ed2f4ec 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 59dc8b197ecb4b6912c9ec29f83f21c405ef8634..48570242fb2dda31a5684e2d678d40690d3c4cab 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 823f2a4638c5b53671e294faf7a99a56d17c897a..50ba2e469f48f1bc16c3f6e3b6f6451a9e29637a 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 1b5f61aa0b85ec592c6efbfa8be08fe83f576be5..3a23477ce72763b562258a25c3777dd57ac1a962 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 ced35b2f532dde3580f162a0c23b642002a0e508..12622fc49a0825fa8423c46ddddc06ff89f292d4 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 dfd4d0c2233df09b64a10d1ad31a36afaa01ec7c..bc1ac77495347967c941298e2da38f76d5d124c6 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 df17d49b87c260c6f5b3fd75d4aad41b77fcf8c3..3f9d9c6db39e030c82e1159043c45c834a47012c 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 1cab91b53455e0129e6c4940a2698620e2197624..2d4bbfcaf4cc2d2b92ad827662dc3b4b4ef355c0 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 68dc1879fe912b1a01b3caa6b1c0168f6a7b8072..765d4b312ed6f062180e83fa0d931e6bd2eef24f 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 4e00b315ff7450efb4a48ba184c6d65991d53c58..c4024d0edd9f77c49e6211c6950c6ccb775a70ff 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 9de8caf5d11445f6db7193f7b7a4151c97befb29..5d91a7e5b3a40cbf41f03a81799c162775c36607 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 98c459dc82be46be706b1d7545d7ec95efd8790c..e10fa88b8cf98b796fc9354e7671dc7bec25840d 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 3b4a390005b07c86ee320ee8ca1cf57e46458cb6..ff5c0bc27a416de16f106c15b9076082c6509e42 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 37ce9a17fc3d66c402954246c83d0ec93fe007af..722d704ff2de1abd3d77a18ca396ba96d5cab6bc 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 1686a54d22a746036b997d6eb8d5b85ca1d79c5d..c85a52c0cc27a187abbdea17cd25cec51b808064 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 af6d2b995a050007ae088dec8e2c3474e9f06ad5..d78e121c76ef12b2d72fbdf1558fa967dfdba85b 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 293bb15d206e71f57e906b33ca27ee05e3429521..6d8c24bb1e68e86d70d4a68d02e3a4d5ccb94c2a 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 9a5cdafa9cb8c5af8a3903ae18297a23adab0fbf..369f91d3b949b23682c4deda8234f13513f15732 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 459a394dc0eb2c7ebecc7c9cf53808d791187006..1dcd1e7f1ede3382ae992a266f5437fe06f8dc75 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 076c18ecc3fc9dc77d1be5dc6e960da72c519576..82fd72652b6d35837b8786005024263ac61630dd 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 3a6c6ea5259693db4846b91855675218b1e1a920..b18768e0aedfbf246173293f74049456070deec3 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 00e77229ddadcb8a13b10b693a96bd76a4cb9f33..136c1b6afa6bc9cee85b018cd5df66c639c3fc91 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 f5346ed32a1b5caf908021805214fd97e033eb27..7467baf2d6c81f94a7d043dcde13d463b3b46272 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 9e1f63ed8dbe8b087f99292880059642d9744697..2ab42aaf4da38b4ea45ef7f0a0f6b807313d4a22 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 65a594c9851689b724cd6a243476679e724fb590..59bbcdb1323cb70432e90ccc2d6a1c60a562c706 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 fc1586350f94ae48e7e48a51818517b465e7a40d..8506286dd271d4e92369d81ec2cce9240a559d64 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 acefaaf41a4e26e45225f6d228734c93c8f2b23c..88b1f43e05e64f0e8dcd6dd0461bbebd6fab1e25 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 05f8fb4771b1ef07030338a6fd38dc7cb3bc1d1d..0bedde41f077f7c6e6106b144854c208ed4f6076 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 8dd104ee0b247f5536d02d54a932acfcbaec603b..3c14ade9dddd06001d9c6d5fab23a9a6b7ca2580 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 71be2a9364748668996696f6c74057dba43315b5..43caff2ffe185df6ab224b93b4fd9ce3d82de2d0 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 b0a4029c94d1bdb1c673fe604cdbfec93df875aa..c6dd71a7bcd0dfcb4691c9ca66a0c3a7bd4dcaae 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 957be9f9269c657fb094b1b3daa4f309c1324ae0..8470850415c14cad8ceeca9f6baef46ab6feabc3 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 9d524000b5ba4d9c7566edd5756b68d728ec362b..379a03131fbd84fb2b45a6b05e62daf82b7e4947 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 62be1bbfd6659f9dfac73a17acd1e2d5322dac66..7f5011f75ef9eb549b33861d9546f3d18a94c256 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 9d30ddb28df16f834c9fbb3bf6ba8cc172a502b3..b194ea3cea531f3a6c81d6d27b5b3028641ba9ce 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 b4cf8c53e0ebbee65a0e4bc0ac1afd1173d1b8e8..a89ae831dd6251d7332e06470273d30fd9cb31eb 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 edc40ff5748fbd68b64f382c251c6b030cf88803..0271285fad6ad532a6133838f7188498476fd77b 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 a8dd8c989c5a135e14c6fc06ea3b23f4f0cd0bec..6208703c061abb868201073795cf516bf81b2602 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 b065061392718e4250d2c52dc3d53a0c1c7938e9..c0fbcdcf4f3447c29c4058907ea2e25fa6d225a6 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 4484185afc4c144bc0d88d9c3832cbeb1515841b..dc86b0d9a997f98ad43ca2897055a92b8a3eb7d0 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 ce2ef6bede40fde8823336bc85762bd3e7cd4760..4a9729b9b388a1e589e9250d8157e723c68140de 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 69cc683332a04ddc6959fcef3d2853ccfb2860b8..b8e9e5ba01658bbdd6e9d712b00da902b6f33fbe 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 a4a4f2ce4c3f147062070c2acc08eaf9f4d40be8..fc00d794d641c146023a78d7d8e4143f0fdac302 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 3aaec7bed76af9efdfe5647be0da64373db2011e..c043066845e03e47093f88ca0b01c7bdef7bffdd 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 4543d113113f90d7fb262b5fe54cbe5f6dfe29fd..26617546c8cadac493f06473d02f27f320713b28 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 97802585ea3ac69ac6ed2e7995605bdcae84558e..214d7ef2b12d41e8d70539fe4a4b16fde71a780a 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 62957ededdf72b93f088586f5d577ef8d38a7f6c..f4358b9d230f6d8d7a9a67fdfbc60279c5ec71ee 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 64e45bd8137bef2b6cfe1f8a3da79e2ff6f8fc47..bd7880dc04830253daae932ba534f02db85f6d2a 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 34f9acee910406c7ba0bf9eed76267a0cf8f46c2..0048f9ef7fee24e5e058ef226f3b0fc93703fcf1 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 2c3a69adc674bb3f539d29b2d29116e89f887066..1283068fd24c371e39f0271d01dd6b3aac437d4b 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 5679170e82ed644d4c3eb4f71f26aa0ac9acce24..51ceb19d88918445c90eccc37f1fe5f90cedd385 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 eff52687a87b45b766e064eede7c2c35b6d133d2..7d68ef714eee5011d82952ca1829016c90827f61 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 06320f5285988365b8340e110427866e68536b47..5089502800d5f477f47b6cd6499d278097f11e67 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 e20fcf3e935dfafb4e30f24990aa974c8b2f5927..e8719aa9e9f47c30b697332925fcdd206fdfd55c 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 4ef1c4f508b0261e725c360e96f2b8cbed50e9ce..d311491e492787ae50aa172f51629abea53eec19 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 2928107bb135004e11f6a11a625067545680b62a..0d101e4913f380a0eda0b3bf9e1d8b76e34c6fd8 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 61626912e3bca2571b41fd1256067470dc170cc1..655fa89d8a7ffe3c3823080f5af3e5e385e95440 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 3cf51665816abb5e5855c036f102019eded23bd6..26ec8c0d1cebcf5e79564be690517cd2eb9c6413 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 f3b8c44181776a99c3eb79e15542104d67001c9d..54756dbb05ba99ab1679f17a50f04c3f1cede8e6 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 c5bfb39b3949430cd06093afdbc85ecc22f8c9c7..9a8e3365827d303c6513475726113a3952fe0040 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 e81e752ed2716ac9fb4a6847f97db84764694b4c..0e3e74304138ab2f279c74599ee934ade72ae37d 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 c72f100f40ce2ab9ae7abead730ed00c2a461fbf..a45f8d66df8d1e452d9392945bf12a74c32bbca9 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 1c5a14922f255af2c3b0e75e06925b748d3d7684..b58aa69fa0609dad7f591024f9da31dfa58496fb 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 6008ac9f1b8d056e522d5fe83c8d56bff314ca92..0d4b64d076b8041a3701715a83ca46a4675ac9d6 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 914ae5759f6932c28ee39afec1e36d80c8e63cd9..71038fcf1cd04fdfa3bcd133b6fc82974a135141 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 733ac39a32f6fd0b4f1546d429ac55c4ad6699b6..57245a8c01fa3aba4f9e3f2bc258b40f38f446c0 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 7051a83a59758277dd60fe026dea730eb7b6b115..82f5ed3ddc8adb1b9b281c3912f4e67c53ef152f 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 ## zip archive frontend for git-fast-import
 ##
index 854cd94ba55e498a3ff6c26be3dbe5191faa19dc..046cb2b268a82358630e86bb55cf8b4e58c730fb 100755 (executable)
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#!/usr/bin/env python
 
 """ hg-to-git.py - A Mercurial to GIT converter
 
index 58a35c82870c54f844fd1154a82237891655f38f..30ae63d74da065a31cced0b161708680f39c04c0 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 0f3d97b67eef3108728265e26f5d79c4526d11ac..b6e534b65b687d955a878d902b9bb46cfa2e42ce 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 7d9e1c03e88d7785f4ff0d534563ba5778fbc244..a90ab10505a3694de83a0ffd8fc472518f12cf2b 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 002aa3c8d6d4ff08d8790a155b8979bc117a2b95..6bae49ca330a69df5e2cf29e1e461f2490d99b2f 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 aae8e7accc1ff955bd76c62b379b37f343f61cc4..4cd9dacbe8e98d1420ebe1a217b0f927d24d125a 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 f5d93e9694d2f5e78bfa3d8dc886968d7cdd5867..230c310952f0296d195c32fbe18b26b279b3fd54 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 cb83332a261f97026f9c6273afb162245944dec7..5615f33af187f381f8c2dfe7ab53910fe165fd59 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 b2c07c70ce26312d81f499d3acf90dab919f1d24..bf225706ee377b89035eb21f76f9957cfaf6363b 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 21f1330a5bf26c955051ce9cf263289d90c7667b..27fc79347af428dd39daa5b550814cc6cf980510 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 1056075545ad3e5e42626d167c91c1deada6186b..87ffae252b3f2ff88646d142ea9c2dfb38a28953 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 3ebf96690aa20eca0f7147d14826a6a4c4bdf777..c0198dde4c2c6a61718228ca2ade463c22e0bec3 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 d975d072dbf0fab36266c3f3a71a69875206e4d8..adc42de8752fd395707f1e395c61991b3146cebb 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 6a65f255cc63cc7a6d0ae0fc0ce4b65298a40e82..f6080149c22bad8b3434b874b9e4079ac508ca69 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*)
index 1a4729f7bb29205fb7bc251887dcd4f5237f1659..a09a44ec4ce3d82cebc5f972f09e94c7c35dc948 100755 (executable)
@@ -43,6 +43,7 @@ merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
 rebase=$(git config --bool branch.$curr_branch_short.rebase)
+dry_run=
 while :
 do
        case "$1" in
@@ -104,6 +105,9 @@ do
        --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
                rebase=false
                ;;
+       --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
+               dry_run=--dry-run
+               ;;
        -h|--h|--he|--hel|--help)
                usage
                ;;
@@ -216,7 +220,8 @@ test true = "$rebase" && {
        done
 }
 orig_head=$(git rev-parse -q --verify HEAD)
-git fetch $verbosity $progress --update-head-ok "$@" || exit 1
+git fetch $verbosity $progress $dry_run --update-head-ok "$@" || exit 1
+test -z "$dry_run" || exit 0
 
 curr_head=$(git rev-parse -q --verify HEAD)
 if test -n "$orig_head" && test "$curr_head" != "$orig_head"
index 415ae72dbc298d7723cdd23b1396c8a6d24dbe08..436b7f5977c05c347debc12130f822af482c03e3 100755 (executable)
@@ -20,6 +20,7 @@ v,verbose          display a diffstat of what changed upstream
 onto=              rebase onto given branch instead of upstream
 p,preserve-merges  try to recreate merges instead of ignoring them
 s,strategy=        use the given merge strategy
+no-ff              cherry-pick all commits, even if unchanged
 m,merge            always used (no-op)
 i,interactive      always used (no-op)
  Actions:
@@ -110,6 +111,7 @@ VERBOSE=
 OK_TO_SKIP_PRE_REBASE=
 REBASE_ROOT=
 AUTOSQUASH=
+NEVER_FF=
 
 GIT_CHERRY_PICK_HELP="  After resolving the conflicts,
 mark the corrected paths with 'git add <paths>', and
@@ -230,8 +232,9 @@ do_with_author () {
 }
 
 pick_one () {
-       no_ff=
-       case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac
+       ff=--ff
+       case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
+       case "$NEVER_FF" in '') ;; ?*) ff= ;; esac
        output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
        test -d "$REWRITTEN" &&
                pick_one_preserving_merges "$@" && return
@@ -240,16 +243,7 @@ pick_one () {
                output git cherry-pick "$@"
                return
        fi
-       parent_sha1=$(git rev-parse --verify $sha1^) ||
-               die "Could not get the parent of $sha1"
-       current_sha1=$(git rev-parse --verify HEAD)
-       if test -z "$no_ff" && test "$current_sha1" = "$parent_sha1"
-       then
-               output git reset --hard $sha1
-               output warn Fast-forward to $(git rev-parse --short $sha1)
-       else
-               output git cherry-pick "$@"
-       fi
+       output git cherry-pick $ff "$@"
 }
 
 pick_one_preserving_merges () {
@@ -484,7 +478,7 @@ do_next () {
                mark_action_done
                pick_one $sha1 ||
                        die_with_patch $sha1 "Could not apply $sha1... $rest"
-               echo "$1" > "$DOTEST"/stopped-sha
+               echo "$sha1" > "$DOTEST"/stopped-sha
                make_patch $sha1
                git rev-parse --verify HEAD > "$AMEND"
                warn "Stopped at $sha1... $rest"
@@ -571,6 +565,7 @@ do_next () {
                        git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
        } &&
        {
+               test -s "$REWRITTEN_LIST" &&
                git notes copy --for-rewrite=rebase < "$REWRITTEN_LIST" ||
                true # we don't care if this copying failed
        } &&
@@ -732,9 +727,10 @@ first and then run 'git rebase --continue' again."
                                test -n "$amend" && git reset --soft $amend
                                die "Could not commit staged changes."
                        }
-                       record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
                fi
 
+               record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
+
                require_clean_work_tree
                do_rest
                ;;
@@ -790,6 +786,9 @@ first and then run 'git rebase --continue' again."
        -i)
                # yeah, we know
                ;;
+       --no-ff)
+               NEVER_FF=t
+               ;;
        --root)
                REBASE_ROOT=t
                ;;
@@ -831,8 +830,6 @@ first and then run 'git rebase --continue' again."
 
                if test ! -z "$1"
                then
-                       output git show-ref --verify --quiet "refs/heads/$1" ||
-                               die "Invalid branchname: $1"
                        output git checkout "$1" ||
                                die "Could not checkout $1"
                fi
@@ -975,7 +972,7 @@ EOF
                has_action "$TODO" ||
                        die_abort "Nothing to do"
 
-               test -d "$REWRITTEN" || skip_unnecessary_picks
+               test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks
 
                git update-ref ORIG_HEAD $HEAD
                output git checkout $ONTO && do_rest
index e0eb9568f3d12a068d46196d2dc896dde4d35fd3..44f5c65fdb5e81c4b660a666c2edd71aa75c5c1a 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
+USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
 LONG_USAGE='git-rebase replaces <branch> with a new branch of the
 same name.  When the --onto option is provided the new branch starts
 out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -353,7 +353,7 @@ do
        --root)
                rebase_root=t
                ;;
-       -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase)
+       -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff)
                force_rebase=t
                ;;
        --rerere-autoupdate|--no-rerere-autoupdate)
index d612ae8729e0a15f501214b6f27f4fc32a66e9fd..111c981229bf2c0bc6afa4a22db011b68d93fdfa 100755 (executable)
@@ -64,6 +64,8 @@ git send-email [options] <file | directory | rev-list options >
     --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
     --smtp-encryption       <str>  * tls or ssl; anything else disables.
     --smtp-ssl                     * Deprecated. Use '--smtp-encryption ssl'.
+    --smtp-domain           <str>  * The domain name sent to HELO/EHLO handshake
+    --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.
 
   Automating:
     --identity              <str>  * Use the sendemail.<id> options.
@@ -162,9 +164,12 @@ my $compose_filename;
 
 # Handle interactive edition of files.
 my $multiedit;
-my $editor = Git::command_oneline('var', 'GIT_EDITOR');
+my $editor;
 
 sub do_edit {
+       if (!defined($editor)) {
+               $editor = Git::command_oneline('var', 'GIT_EDITOR');
+       }
        if (defined($multiedit) && !$multiedit) {
                map {
                        system('sh', '-c', $editor.' "$@"', $editor, $_);
@@ -183,10 +188,12 @@ sub do_edit {
 # Variables with corresponding config settings
 my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
 my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
-my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
+my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts, $smtp_domain);
 my ($validate, $confirm);
 my (@suppress_cc);
 
+my ($debug_net_smtp) = 0;              # Net::SMTP, see send_message()
+
 my $not_set_by_user = "true but not set by the user";
 
 my %config_bool_settings = (
@@ -203,6 +210,7 @@ my %config_settings = (
     "smtpserverport" => \$smtp_server_port,
     "smtpuser" => \$smtp_authuser,
     "smtppass" => \$smtp_authpass,
+       "smtpdomain" => \$smtp_domain,
     "to" => \@to,
     "cc" => \@initial_cc,
     "cccmd" => \$cc_cmd,
@@ -273,6 +281,8 @@ my $rc = GetOptions("sender|from=s" => \$sender,
                    "smtp-pass:s" => \$smtp_authpass,
                    "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
                    "smtp-encryption=s" => \$smtp_encryption,
+                   "smtp-debug:i" => \$debug_net_smtp,
+                   "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
                    "annotate" => \$annotate,
                    "compose" => \$compose,
@@ -750,8 +760,7 @@ sub extract_valid_address {
 # We'll setup a template for the message id, using the "from" address:
 
 my ($message_id_stamp, $message_id_serial);
-sub make_message_id
-{
+sub make_message_id {
        my $uniq;
        if (!defined $message_id_stamp) {
                $message_id_stamp = sprintf("%s-%s", time, $$);
@@ -806,8 +815,7 @@ sub is_rfc2047_quoted {
 }
 
 # use the simplest quoting being able to handle the recipient
-sub sanitize_address
-{
+sub sanitize_address {
        my ($recipient) = @_;
        my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
 
@@ -836,12 +844,67 @@ sub sanitize_address
 
 }
 
+# Returns the local Fully Qualified Domain Name (FQDN) if available.
+#
+# Tightly configured MTAa require that a caller sends a real DNS
+# domain name that corresponds the IP address in the HELO/EHLO
+# handshake. This is used to verify the connection and prevent
+# spammers from trying to hide their identity. If the DNS and IP don't
+# match, the receiveing MTA may deny the connection.
+#
+# Here is a deny example of Net::SMTP with the default "localhost.localdomain"
+#
+# Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
+# Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
+#
+# This maildomain*() code is based on ideas in Perl library Test::Reporter
+# /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
+
+sub valid_fqdn {
+       my $domain = shift;
+       return !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
+}
+
+sub maildomain_net {
+       my $maildomain;
+
+       if (eval { require Net::Domain; 1 }) {
+               my $domain = Net::Domain::domainname();
+               $maildomain = $domain if valid_fqdn($domain);
+       }
+
+       return $maildomain;
+}
+
+sub maildomain_mta {
+       my $maildomain;
+
+       if (eval { require Net::SMTP; 1 }) {
+               for my $host (qw(mailhost localhost)) {
+                       my $smtp = Net::SMTP->new($host);
+                       if (defined $smtp) {
+                               my $domain = $smtp->domain;
+                               $smtp->quit;
+
+                               $maildomain = $domain if valid_fqdn($domain);
+
+                               last if $maildomain;
+                       }
+               }
+       }
+
+       return $maildomain;
+}
+
+sub maildomain {
+       return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
+}
+
 # Returns 1 if the message was sent, and 0 otherwise.
 # In actuality, the whole program dies when there
 # is an error sending a message.
 
-sub send_message
-{
+sub send_message {
        my @recipients = unique_email_list(@to);
        @cc = (grep { my $cc = extract_valid_address($_);
                      not grep { $cc eq $_ } @recipients
@@ -938,13 +1001,19 @@ X-Mailer: git-send-email $gitversion
                if ($smtp_encryption eq 'ssl') {
                        $smtp_server_port ||= 465; # ssmtp
                        require Net::SMTP::SSL;
-                       $smtp ||= Net::SMTP::SSL->new($smtp_server, Port => $smtp_server_port);
+                       $smtp_domain ||= maildomain();
+                       $smtp ||= Net::SMTP::SSL->new($smtp_server,
+                                                     Hello => $smtp_domain,
+                                                     Port => $smtp_server_port);
                }
                else {
                        require Net::SMTP;
+                       $smtp_domain ||= maildomain();
                        $smtp ||= Net::SMTP->new((defined $smtp_server_port)
                                                 ? "$smtp_server:$smtp_server_port"
-                                                : $smtp_server);
+                                                : $smtp_server,
+                                                Hello => $smtp_domain,
+                                                Debug => $debug_net_smtp);
                        if ($smtp_encryption eq 'tls' && $smtp) {
                                require Net::SMTP::SSL;
                                $smtp->command('STARTTLS');
@@ -963,7 +1032,11 @@ X-Mailer: git-send-email $gitversion
                }
 
                if (!$smtp) {
-                       die "Unable to initialize SMTP properly.  Is there something wrong with your config?";
+                       die "Unable to initialize SMTP properly. Check config and use --smtp-debug. ",
+                           "VALUES: server=$smtp_server ",
+                           "encryption=$smtp_encryption ",
+                           "hello=$smtp_domain",
+                           defined $smtp_server_port ? "port=$smtp_server_port" : "";
                }
 
                if (defined $smtp_authuser) {
index aa47e541ee4fe55254edc3fb59ef534ba4d5be66..0f858d334c756f9cd4028b4950a3912d0f6182dd 100755 (executable)
@@ -86,7 +86,7 @@ create_stash () {
                        GIT_INDEX_FILE="$TMP-index" &&
                        export GIT_INDEX_FILE &&
                        git read-tree -m $i_tree &&
-                       git add -u &&
+                       git diff --name-only -z HEAD | git update-index -z --add --remove --stdin &&
                        git write-tree &&
                        rm -f "$TMP-index"
                ) ) ||
@@ -210,14 +210,18 @@ list_stash () {
 }
 
 show_stash () {
+       have_stash || die 'No stash found'
+
        flags=$(git rev-parse --no-revs --flags "$@")
        if test -z "$flags"
        then
                flags=--stat
        fi
 
-       w_commit=$(git rev-parse --verify --default $ref_stash "$@") &&
-       b_commit=$(git rev-parse --verify "$w_commit^") &&
+       w_commit=$(git rev-parse --quiet --verify --default $ref_stash "$@") &&
+       b_commit=$(git rev-parse --quiet --verify "$w_commit^") ||
+               die "'$*' is not a stash"
+
        git diff $flags $b_commit $w_commit
 }
 
index 2dd372a21d82a109774e80e014f9959485202b3e..3319b836b217a26b4ac55ae5ced328ffafa0a015 100755 (executable)
@@ -21,6 +21,8 @@ command=
 branch=
 reference=
 cached=
+recursive=
+init=
 files=
 nofetch=
 update=
index ee74a5eed7758f1267441d85619969a121fb3cec..9533147ff2e06282dc8d60aeb371afa715e22cc1 100644 (file)
@@ -127,6 +127,9 @@ find $RPM_BUILD_ROOT -type f -name perllocal.pod -exec rm -f {} ';'
 rm -rf $RPM_BUILD_ROOT%{_mandir}
 %endif
 
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
+install -m 644 -T contrib/completion/git-completion.bash $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/git
+
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -136,6 +139,7 @@ rm -rf $RPM_BUILD_ROOT
 %doc README COPYING Documentation/*.txt
 %{!?_without_docs: %doc Documentation/*.html Documentation/howto}
 %{!?_without_docs: %doc Documentation/technical}
+%{_sysconfdir}/bash_completion.d
 
 %files svn
 %defattr(-,root,root)
@@ -192,6 +196,9 @@ rm -rf $RPM_BUILD_ROOT
 # No files for you!
 
 %changelog
+* Fri Mar 26 2010 Ian Ward Comfort <icomfort@stanford.edu>
+- Ship bash completion support from contrib/ in the core package.
+
 * Sun Jan 31 2010 Junio C Hamano <gitster@pobox.com>
 - Do not use %define inside %{!?...} construct.
 
index c62dfd0f4ddafbc82be15519f17815bbfcd62e8b..74b05dc91e42414147d5f3dc7b4fc66fb86c0eca 100644 (file)
@@ -7,7 +7,11 @@ pysetupfile:=setup.py
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 
 ifndef PYTHON_PATH
-       PYTHON_PATH = /usr/bin/python
+       ifeq ($(uname_S),FreeBSD)
+               PYTHON_PATH = /usr/local/bin/python
+       else
+               PYTHON_PATH = /usr/bin/python
+       endif
 endif
 ifndef prefix
        prefix = $(HOME)
index 1f36a3e815865fcc72b171b497f5c4e341e148ee..1b0e09a561e01c51bdc6dbced052e0c753924618 100644 (file)
@@ -1877,8 +1877,11 @@ proc setoptions {} {
     option add *Menubutton.font uifont startupFile
     option add *Label.font uifont startupFile
     option add *Message.font uifont startupFile
-    option add *Entry.font uifont startupFile
+    option add *Entry.font textfont startupFile
+    option add *Text.font textfont startupFile
     option add *Labelframe.font uifont startupFile
+    option add *Spinbox.font textfont startupFile
+    option add *Listbox.font mainfont startupFile
 }
 
 # Make a menu and submenus.
@@ -2174,7 +2177,7 @@ proc makewindow {} {
     set findstring {}
     set fstring .tf.lbar.findstring
     lappend entries $fstring
-    ${NS}::entry $fstring -width 30 -font textfont -textvariable findstring
+    ${NS}::entry $fstring -width 30 -textvariable findstring
     trace add variable findstring write find_change
     set findtype [mc "Exact"]
     set findtypemenu [makedroplist .tf.lbar.findtype \
@@ -2217,7 +2220,7 @@ proc makewindow {} {
     pack .bleft.top.search -side left -padx 5
     set sstring .bleft.top.sstring
     set searchstring ""
-    ${NS}::entry $sstring -width 20 -font textfont -textvariable searchstring
+    ${NS}::entry $sstring -width 20 -textvariable searchstring
     lappend entries $sstring
     trace add variable searchstring write incrsearch
     pack $sstring -side left -expand 1 -fill x
@@ -2229,7 +2232,7 @@ proc makewindow {} {
        -command changediffdisp -variable diffelide -value {1 0}
     ${NS}::label .bleft.mid.labeldiffcontext -text "      [mc "Lines of context"]: "
     pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
-    spinbox .bleft.mid.diffcontext -width 5 -font textfont \
+    spinbox .bleft.mid.diffcontext -width 5 \
        -from 0 -increment 1 -to 10000000 \
        -validate all -validatecommand "diffcontextvalidate %P" \
        -textvariable diffcontextstring
@@ -2383,6 +2386,8 @@ proc makewindow {} {
     }
     bindall <$::BM> "canvscan mark %W %x %y"
     bindall <B$::BM-Motion> "canvscan dragto %W %x %y"
+    bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
+    bind . <$M1B-Key-w> doquit
     bindkey <Home> selfirstline
     bindkey <End> sellastline
     bind . <Key-Up> "selnextline -1"
@@ -2782,7 +2787,7 @@ proc about {} {
     message $w.m -text [mc "
 Gitk - a commit viewer for git
 
-Copyright © 2005-2009 Paul Mackerras
+Copyright \u00a9 2005-2010 Paul Mackerras
 
 Use and redistribute under the terms of the GNU General Public License"] \
            -justify center -aspect 400 -border 2 -bg white -relief groove
@@ -2814,6 +2819,7 @@ proc keys {} {
 [mc "Gitk key bindings:"]
 
 [mc "<%s-Q>            Quit" $M1T]
+[mc "<%s-W>            Close window" $M1T]
 [mc "<Home>            Move to first commit"]
 [mc "<End>             Move to last commit"]
 [mc "<Up>, p, i        Move up one commit"]
@@ -3805,10 +3811,10 @@ proc newview {ishighlight} {
        raise $top
        return
     }
+    decode_view_opts $nextviewnum $revtreeargs
     set newviewname($nextviewnum) "[mc "View"] $nextviewnum"
     set newviewopts($nextviewnum,perm) 0
     set newviewopts($nextviewnum,cmd)  $viewargscmd($curview)
-    decode_view_opts $nextviewnum $revtreeargs
     vieweditor $top $nextviewnum [mc "Gitk view definition"]
 }
 
@@ -3845,6 +3851,7 @@ set known_view_options {
     {cmd       t50= +  {}               {mc "Command to generate more commits to include:"}}
     }
 
+# Convert $newviewopts($n, ...) into args for git log.
 proc encode_view_opts {n} {
     global known_view_options newviewopts
 
@@ -3878,6 +3885,7 @@ proc encode_view_opts {n} {
     return [concat $rargs [shellsplit $newviewopts($n,args)]]
 }
 
+# Fill $newviewopts($n, ...) based on args for git log.
 proc decode_view_opts {n view_args} {
     global known_view_options newviewopts
 
@@ -3960,10 +3968,10 @@ proc editview {} {
        raise $top
        return
     }
+    decode_view_opts $curview $viewargs($curview)
     set newviewname($curview)      $viewname($curview)
     set newviewopts($curview,perm) $viewperm($curview)
     set newviewopts($curview,cmd)  $viewargscmd($curview)
-    decode_view_opts $curview $viewargs($curview)
     vieweditor $top $curview "[mc "Gitk: edit view"] $viewname($curview)"
 }
 
@@ -4037,7 +4045,7 @@ proc vieweditor {top n title} {
        } elseif {$type eq "path"} {
            ${NS}::label $top.l -text $title
            pack $top.l -in $top -side top -pady [list 3 0] -anchor w -padx 3
-           text $top.t -width 40 -height 5 -background $bgcolor -font uifont
+           text $top.t -width 40 -height 5 -background $bgcolor
            if {[info exists viewfiles($n)]} {
                foreach f $viewfiles($n) {
                    $top.t insert end $f
@@ -7501,7 +7509,7 @@ proc getblobdiffs {ids} {
     global ignorespace
     global limitdiffs vfilelimit curview
     global diffencoding targetline diffnparents
-    global git_version
+    global git_version currdiffsubmod
 
     set textconv {}
     if {[package vcompare $git_version "1.6.1"] >= 0} {
@@ -7528,6 +7536,7 @@ proc getblobdiffs {ids} {
     set diffencoding [get_path_encoding {}]
     fconfigure $bdf -blocking 0 -encoding binary -eofchar {}
     set blobdifffd($ids) $bdf
+    set currdiffsubmod ""
     filerun $bdf [list getblobdiffline $bdf $diffids]
 }
 
@@ -7598,7 +7607,7 @@ proc getblobdiffline {bdf ids} {
     global diffnexthead diffnextnote difffilestart
     global ctext_file_names ctext_file_lines
     global diffinhdr treediffs mergemax diffnparents
-    global diffencoding jump_to_here targetline diffline
+    global diffencoding jump_to_here targetline diffline currdiffsubmod
 
     set nr 0
     $ctext conf -state normal
@@ -7679,19 +7688,30 @@ proc getblobdiffline {bdf ids} {
 
        } elseif {![string compare -length 10 "Submodule " $line]} {
            # start of a new submodule
-           if {[string compare [$ctext get "end - 4c" end] "\n \n\n"]} {
+           if {[regexp -indices "\[0-9a-f\]+\\.\\." $line nameend]} {
+               set fname [string range $line 10 [expr [lindex $nameend 0] - 2]]
+           } else {
+               set fname [string range $line 10 [expr [string first "contains " $line] - 2]]
+           }
+           if {$currdiffsubmod != $fname} {
                $ctext insert end "\n";     # Add newline after commit message
            }
            set curdiffstart [$ctext index "end - 1c"]
            lappend ctext_file_names ""
-           set fname [string range $line 10 [expr [string last " " $line] - 1]]
-           lappend ctext_file_lines $fname
-           makediffhdr $fname $ids
-           $ctext insert end "\n$line\n" filesep
+           if {$currdiffsubmod != $fname} {
+               lappend ctext_file_lines $fname
+               makediffhdr $fname $ids
+               set currdiffsubmod $fname
+               $ctext insert end "\n$line\n" filesep
+           } else {
+               $ctext insert end "$line\n" filesep
+           }
        } elseif {![string compare -length 3 "  >" $line]} {
+           set $currdiffsubmod ""
            set line [encoding convertfrom $diffencoding $line]
            $ctext insert end "$line\n" dresult
        } elseif {![string compare -length 3 "  <" $line]} {
+           set $currdiffsubmod ""
            set line [encoding convertfrom $diffencoding $line]
            $ctext insert end "$line\n" d0
        } elseif {$diffinhdr} {
@@ -8527,7 +8547,7 @@ proc do_cmp_commits {a b} {
 }
 
 proc diffcommits {a b} {
-    global diffcontext diffids blobdifffd diffinhdr
+    global diffcontext diffids blobdifffd diffinhdr currdiffsubmod
 
     set tmpdir [gitknewtmpdir]
     set fna [file join $tmpdir "commit-[string range $a 0 7]"]
@@ -8548,6 +8568,7 @@ proc diffcommits {a b} {
     set diffids [list commits $a $b]
     set blobdifffd($diffids) $fd
     set diffinhdr 0
+    set currdiffsubmod ""
     filerun $fd [list getblobdiffline $fd $diffids]
 }
 
@@ -10528,7 +10549,6 @@ proc mkfontdisp {font top which} {
     set fontpref($font) [set $font]
     ${NS}::button $top.${font}but -text $which \
        -command [list choosefont $font $which]
-    if {!$use_ttk} {$top.${font}but configure  -font optionfont}
     ${NS}::label $top.$font -relief flat -font $font \
        -text $fontattr($font,family) -justify left
     grid x $top.${font}but $top.$font -sticky w
@@ -10791,15 +10811,6 @@ proc doprefs {} {
     mkfontdisp textfont $top [mc "Diff display font"]
     mkfontdisp uifont $top [mc "User interface font"]
 
-    if {!$use_ttk} {
-       foreach w {maxpctl maxwidthl showlocal autoselect tabstopl ntag
-           ldiff lattr extdifff.l extdifff.b bgbut fgbut
-           diffoldbut diffnewbut hunksepbut markbgbut selbgbut
-           want_ttk ttk_note} {
-           $top.$w configure -font optionfont
-       }
-    }
-
     ${NS}::frame $top.buts
     ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
     ${NS}::button $top.buts.can -text [mc "Cancel"] -command prefscan -default normal
@@ -10849,6 +10860,7 @@ proc setselbg {c} {
 # radiobuttons look bad.  This chooses white for selectColor if the
 # background color is light, or black if it is dark.
 proc setui {c} {
+    if {[tk windowingsystem] eq "win32"} { return }
     set bg [winfo rgb . $c]
     set selc black
     if {[lindex $bg 0] + 1.5 * [lindex $bg 1] + 0.5 * [lindex $bg 2] > 100000} {
@@ -11411,8 +11423,6 @@ namespace import ::msgcat::mc
 
 catch {source ~/.gitk}
 
-font create optionfont -family sans-serif -size -12
-
 parsefont mainfont $mainfont
 eval font create mainfont [fontflags mainfont]
 eval font create mainfontbold [fontflags mainfont 1]
@@ -11613,3 +11623,9 @@ if {[tk windowingsystem] eq "win32"} {
 }
 
 getcommits {}
+
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: t
+# tab-width: 8
+# End:
index c79aa9cbc813dfe13bb39db2eacd1cc7ab49441c..bd194a3dff9fd36b2edbe64f053a975f489a159b 100644 (file)
@@ -334,14 +334,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright ©9 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - eine Visualisierung der Git-Historie\n"
 "\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Benutzung und Weiterverbreitung gemäß den Bedingungen der GNU General Public License"
 
index 0e19b5eae27ed10e6cae524e9dc69cca1b1f428f..0471dd0672d837371fad32db5eddd32207e63c1f 100644 (file)
@@ -281,14 +281,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - un visualizador de revisiones para git\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Uso y redistribución permitidos según los términos de la Licencia Pública "
 "General de GNU (GNU GPL)"
index cb0e1edc634d29f3ddf83ae39c4f9c75d7374326..5370ddc393dfa0b72220d9e572a60be606927da4 100644 (file)
@@ -334,14 +334,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - visualisateur de commit pour git\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Utilisation et redistribution soumises aux termes de la GNU General Public "
 "License"
index 1df212e8817258da3bf870997e42e75fad09fe95..7262b610dc0489ce9bcc4512a7e02bba5c758682 100644 (file)
@@ -333,14 +333,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright ©9 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - commit nézegető a githez\n"
 "\n"
-"Szerzői jog ©9 2005-2009 Paul Mackerras\n"
+"Szerzői jog \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Használd és terjeszd a GNU General Public License feltételei mellett"
 
index 4818652309d91e90fb4595b500cb687bcdedcb94..a730d63a42ad380548e454410eafcbadece85387 100644 (file)
@@ -334,14 +334,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - un visualizzatore di revisioni per git\n"
 "\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Utilizzo e redistribuzione permessi sotto i termini della GNU General Public "
 "License"
index c0c92addb41c9e1e59c0f314a7b37b4470dcebbe..4f4705164c0c71b64bee4e833c0960b9344c2ad9 100644 (file)
@@ -335,14 +335,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - gitコミットビューア\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "使用および再配布は GNU General Public License に従ってください"
 
index 704eba8f9d39655099aa66864d1dd34a84bd0a9d..c3d0285b2429d92ca40297bfb2135365ba49f371 100644 (file)
@@ -313,14 +313,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - программа просмотра истории репозиториев Git\n"
 "\n"
-"Copyright (c) 2005-2008 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Использование и распространение согласно условиям GNU General Public License"
 
index 0f5e2fd8d79b585e1487b7ba9e2d1a36a49c7c7d..386763ade786d96b657dd0ab737b633eef44b424 100644 (file)
@@ -334,14 +334,14 @@ msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright ©9 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - en incheckningsvisare för git\n"
 "\n"
-"Copyright © 2005-2009 Paul Mackerras\n"
+"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
 "\n"
 "Använd och vidareförmedla enligt villkoren i GNU General Public License"
 
index b76a0cffff783ba580294560f0ee53131776136b..cbdc1364700d79b9d8b41850790baee103f31ca1 100644 (file)
@@ -2,11 +2,11 @@ GIT web Interface (gitweb) Installation
 =======================================
 
 First you have to generate gitweb.cgi from gitweb.perl using
-"make gitweb/gitweb.cgi", then copy appropriate files (gitweb.cgi,
+"make gitweb", then copy appropriate files (gitweb.cgi, gitweb.js,
 gitweb.css, git-logo.png and git-favicon.png) to their destination.
 For example if git was (or is) installed with /usr prefix, you can do
 
-       $ make prefix=/usr gitweb/gitweb.cgi  ;# as yourself
+       $ make prefix=/usr gitweb             ;# as yourself
        # cp gitweb/git* /var/www/cgi-bin/    ;# as root
 
 Alternatively you can use autoconf generated ./configure script to
@@ -15,7 +15,7 @@ instead
 
        $ make configure                     ;# as yourself
        $ ./configure --prefix=/usr          ;# as yourself
-       $ make gitweb/gitweb.cgi             ;# as yourself
+       $ make gitweb                        ;# as yourself
        # cp gitweb/git* /var/www/cgi-bin/   ;# as root
 
 The above example assumes that your web server is configured to run
@@ -31,8 +31,7 @@ file for gitweb (in gitweb/README).
 
 - There are many configuration variables which affect building of
   gitweb.cgi; see "default configuration for gitweb" section in main
-  (top dir) Makefile, and instructions for building gitweb/gitweb.cgi
-  target.
+  (top dir) Makefile, and instructions for building gitweb target.
 
   One of the most important is where to find the git wrapper binary. Gitweb
   tries to find the git wrapper at $(bindir)/git, so you have to set $bindir
@@ -62,9 +61,15 @@ file for gitweb (in gitweb/README).
   a suggestion).
 
 - You can control where gitweb tries to find its main CSS style file,
-  its favicon and logo with the GITWEB_CSS, GITWEB_FAVICON and GITWEB_LOGO
-  build configuration variables. By default gitweb tries to find them
-  in the same directory as gitweb.cgi script.
+  its JavaScript file, its favicon and logo with the GITWEB_CSS, GITWEB_JS
+  GITWEB_FAVICON and GITWEB_LOGO build configuration variables. By default
+  gitweb tries to find them in the same directory as gitweb.cgi script.
+
+- You can optionally generate minified versions of gitweb.js and gitweb.css
+  by defining the JSMIN and CSSMIN build configuration variables. By default
+  the non-minified versions will be used. NOTE: if you enable this option,
+  substitute gitweb.min.js and gitweb.min.css for all uses of gitweb.js and
+  gitweb.css in the help files.
 
 Build example
 ~~~~~~~~~~~~~
@@ -74,13 +79,14 @@ Build example
   we want to display are under /home/local/scm, you can do
 
        make GITWEB_PROJECTROOT="/home/local/scm" \
+            GITWEB_JS="/gitweb/gitweb.js" \
             GITWEB_CSS="/gitweb/gitweb.css" \
             GITWEB_LOGO="/gitweb/git-logo.png" \
             GITWEB_FAVICON="/gitweb/git-favicon.png" \
             bindir=/usr/local/bin \
-            gitweb/gitweb.cgi
+            gitweb
 
-       cp -fv ~/git/gitweb/gitweb.{cgi,css} \
+       cp -fv ~/git/gitweb/gitweb.{cgi,js,css} \
               ~/git/gitweb/git-{favicon,logo}.png \
             /var/www/cgi-bin/gitweb/
 
index c9eb1ee6678aa180d74e3da3a74537766f0b1fe4..e7dd2527736ddc6e47f864916115f9cc5c9e7dd9 100644 (file)
@@ -6,14 +6,14 @@ 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
+#
 
 prefix ?= $(HOME)
 bindir ?= $(prefix)/bin
 RM ?= rm -f
 
-# JavaScript minifier invocation that can function as filter
-JSMIN ?=
-
 # default configuration for gitweb
 GITWEB_CONFIG = gitweb_config.perl
 GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
@@ -29,11 +29,7 @@ GITWEB_HOMETEXT = indextext.html
 GITWEB_CSS = gitweb.css
 GITWEB_LOGO = git-logo.png
 GITWEB_FAVICON = git-favicon.png
-ifdef JSMIN
-GITWEB_JS = gitweb.min.js
-else
 GITWEB_JS = gitweb.js
-endif
 GITWEB_SITE_HEADER =
 GITWEB_SITE_FOOTER =
 
@@ -85,45 +81,54 @@ endif
 all:: gitweb.cgi
 
 ifdef JSMIN
-FILES=gitweb.cgi gitweb.min.js
-gitweb.cgi: gitweb.perl gitweb.min.js
-else # !JSMIN
-FILES=gitweb.cgi
-gitweb.cgi: gitweb.perl
-endif # JSMIN
-
-gitweb.cgi:
+GITWEB_JS = gitweb.min.js
+all:: gitweb.min.js
+gitweb.min.js: gitweb.js GITWEB-BUILD-OPTIONS
+       $(QUIET_GEN)$(JSMIN) <$< >$@
+endif
+
+ifdef CSSMIN
+GITWEB_CSS = gitweb.min.css
+all:: gitweb.min.css
+gitweb.min.css: gitweb.css GITWEB-BUILD-OPTIONS
+       $(QUIET_GEN)$(CSSMIN) <$< >$@
+endif
+
+GITWEB_REPLACE = \
+       -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
+       -e 's|++GIT_BINDIR++|$(bindir)|g' \
+       -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+       -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
+       -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
+       -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
+       -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
+       -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
+       -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
+       -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
+       -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
+       -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
+       -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
+       -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
+       -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
+       -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
+       -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
+       -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
+       -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g'
+
+GITWEB-BUILD-OPTIONS: FORCE
+       @rm -f $@+
+       @echo "x" '$(PERL_PATH_SQ)' $(GITWEB_REPLACE) "$(JSMIN)|$(CSSMIN)" >$@+
+       @cmp -s $@+ $@ && rm -f $@+ || mv -f $@+ $@
+
+gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-           -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-           -e 's|++GIT_BINDIR++|$(bindir)|g' \
-           -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
-           -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
-           -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
-           -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
-           -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
-           -e 's|"++GITWEB_PROJECT_MAXDEPTH++"|$(GITWEB_PROJECT_MAXDEPTH)|g' \
-           -e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
-           -e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
-           -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
-           -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
-           -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
-           -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
-           -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
-           -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
-           -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
-           -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
-           -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
-           $< >$@+ && \
+               $(GITWEB_REPLACE) $< >$@+ && \
        chmod +x $@+ && \
        mv $@+ $@
 
-ifdef JSMIN
-gitweb.min.js: gitweb.js
-       $(QUIET_GEN)$(JSMIN) <$< >$@
-endif # JSMIN
-
 clean:
-       $(RM) $(FILES)
+       $(RM) gitweb.cgi gitweb.min.js gitweb.min.css GITWEB-BUILD-OPTIONS
+
+.PHONY: all clean .FORCE-GIT-VERSION-FILE FORCE
 
-.PHONY: all clean .FORCE-GIT-VERSION-FILE
index ad6a04c464075c31afe3c67222f0bdeabc76f569..71742b335dd786a24699b06b17519e264724ea5b 100644 (file)
@@ -80,7 +80,8 @@ You can specify the following configuration variables when building GIT:
    Points to the location where you put gitweb.css on your web server
    (or to be more generic, the URI of gitweb stylesheet).  Relative to the
    base URI of gitweb.  Note that you can setup multiple stylesheets from
-   the gitweb config file.  [Default: gitweb.css]
+   the gitweb config file.  [Default: gitweb.css (or gitweb.min.css if the
+   CSSMIN variable is defined / CSS minifier is used)]
  * GITWEB_LOGO
    Points to the location where you put git-logo.png on your web server
    (or to be more generic URI of logo, 72x27 size, displayed in top right
index a2d2283ec921acac7b068537eb85f63c16de9556..c356e95f18f0f784584ce644c08e1966ca1be52f 100755 (executable)
@@ -2216,8 +2216,7 @@ sub config_to_multi {
 sub git_get_project_config {
        my ($key, $type) = @_;
 
-       # do we have project
-       return unless (defined $project && defined $git_dir);
+       return unless defined $git_dir;
 
        # key sanity check
        return unless ($key);
diff --git a/grep.c b/grep.c
index fdc42062687fa6b8bb77c8d09ed58aee9107692d..543b1d53784c16020dea089f23c431c7f2608425 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -570,8 +570,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
                        if (opt->show_hunk_mark) {
                                output_color(opt, "--", 2, opt->color_sep);
                                opt->output(opt, "\n", 1);
-                       } else
-                               opt->show_hunk_mark = 1;
+                       }
                } else if (lno > opt->last_shown + 1) {
                        output_color(opt, "--", 2, opt->color_sep);
                        opt->output(opt, "\n", 1);
@@ -772,14 +771,6 @@ int grep_threads_ok(const struct grep_opt *opt)
            !opt->name_only)
                return 0;
 
-       /* If we are showing hunk marks, we should not do it for the
-        * first match. The synchronization problem we get for this
-        * constraint is not yet solved, so we disable threading in
-        * this case.
-        */
-       if (opt->pre_context || opt->post_context)
-               return 0;
-
        return 1;
 }
 
@@ -801,11 +792,14 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
        enum grep_context ctx = GREP_CONTEXT_HEAD;
        xdemitconf_t xecfg;
 
-       opt->last_shown = 0;
-
        if (!opt->output)
                opt->output = std_output;
 
+       if (opt->last_shown && (opt->pre_context || opt->post_context) &&
+           opt->output == std_output)
+               opt->show_hunk_mark = 1;
+       opt->last_shown = 0;
+
        if (buffer_is_binary(buf, size)) {
                switch (opt->binary) {
                case GREP_BINARY_DEFAULT:
index 345c12b79064f23e0ae0a15781731b9a42272d83..d1e83d0906dbc9d677630cdf74615ec3f9dfc46d 100644 (file)
@@ -538,15 +538,19 @@ static void service_rpc(char *service_name)
 
 static NORETURN void die_webcgi(const char *err, va_list params)
 {
-       char buffer[1000];
+       static int dead;
 
-       http_status(500, "Internal Server Error");
-       hdr_nocache();
-       end_headers();
+       if (!dead) {
+               char buffer[1000];
+               dead = 1;
 
-       vsnprintf(buffer, sizeof(buffer), err, params);
-       fprintf(stderr, "fatal: %s\n", buffer);
-       exit(0);
+               vsnprintf(buffer, sizeof(buffer), err, params);
+               fprintf(stderr, "fatal: %s\n", buffer);
+               http_status(500, "Internal Server Error");
+               hdr_nocache();
+               end_headers();
+       }
+       exit(0); /* we successfully reported a failure ;-) */
 }
 
 static char* getdir(void)
index ef99ae647ae02995495c71455eef785bdeca1789..8ca76d0507bdc1d95283e1f5fee3f88180cdce26 100644 (file)
@@ -510,7 +510,7 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c
                ret = error("File %s has bad hash", hex);
        } else if (req->rename < 0) {
                ret = error("unable to write sha1 filename %s",
-                           req->filename);
+                           sha1_file_name(req->sha1));
        }
 
        release_http_object_request(req);
diff --git a/http.c b/http.c
index 4814217c6401faa1fd8f13f0288758f57b5e3755..1320c50e32eb7b8715b263bc2af089c3dbce39fa 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1,6 +1,7 @@
 #include "http.h"
 #include "pack.h"
 #include "sideband.h"
+#include "run-command.h"
 
 int data_received;
 int active_requests;
@@ -720,7 +721,7 @@ static inline int hex(int v)
                return 'A' + v - 10;
 }
 
-static void end_url_with_slash(struct strbuf *buf, const char *url)
+void end_url_with_slash(struct strbuf *buf, const char *url)
 {
        strbuf_addstr(buf, url);
        if (buf->len && buf->buf[buf->len - 1] != '/')
@@ -815,7 +816,21 @@ static int http_request(const char *url, void *result, int target, int options)
                        ret = HTTP_OK;
                else if (missing_target(&results))
                        ret = HTTP_MISSING_TARGET;
-               else
+               else if (results.http_code == 401) {
+                       if (user_name) {
+                               ret = HTTP_NOAUTH;
+                       } else {
+                               /*
+                                * git_getpass is needed here because its very likely stdin/stdout are
+                                * pipes to our parent process.  So we instead need to use /dev/tty,
+                                * but that is non-portable.  Using git_getpass() can at least be stubbed
+                                * on other platforms with a different implementation if/when necessary.
+                                */
+                               user_name = xstrdup(git_getpass("Username: "));
+                               init_curl_http_auth(slot->curl);
+                               ret = HTTP_REAUTH;
+                       }
+               } else
                        ret = HTTP_ERROR;
        } else {
                error("Unable to start HTTP request for %s", url);
@@ -831,7 +846,11 @@ static int http_request(const char *url, void *result, int target, int options)
 
 int http_get_strbuf(const char *url, struct strbuf *result, int options)
 {
-       return http_request(url, result, HTTP_REQUEST_STRBUF, options);
+       int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+       if (http_ret == HTTP_REAUTH) {
+               http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+       }
+       return http_ret;
 }
 
 /*
@@ -896,47 +915,67 @@ int http_fetch_ref(const char *base, struct ref *ref)
 }
 
 /* Helpers for fetching packs */
-static int fetch_pack_index(unsigned char *sha1, const char *base_url)
+static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
 {
-       int ret = 0;
-       char *hex = xstrdup(sha1_to_hex(sha1));
-       char *filename;
-       char *url = NULL;
+       char *url, *tmp;
        struct strbuf buf = STRBUF_INIT;
 
-       if (has_pack_index(sha1)) {
-               ret = 0;
-               goto cleanup;
-       }
-
        if (http_is_verbose)
-               fprintf(stderr, "Getting index for pack %s\n", hex);
+               fprintf(stderr, "Getting index for pack %s\n", sha1_to_hex(sha1));
 
        end_url_with_slash(&buf, base_url);
-       strbuf_addf(&buf, "objects/pack/pack-%s.idx", hex);
+       strbuf_addf(&buf, "objects/pack/pack-%s.idx", sha1_to_hex(sha1));
        url = strbuf_detach(&buf, NULL);
 
-       filename = sha1_pack_index_name(sha1);
-       if (http_get_file(url, filename, 0) != HTTP_OK)
-               ret = error("Unable to get pack index %s\n", url);
+       strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1));
+       tmp = strbuf_detach(&buf, NULL);
+
+       if (http_get_file(url, tmp, 0) != HTTP_OK) {
+               error("Unable to get pack index %s\n", url);
+               free(tmp);
+               tmp = NULL;
+       }
 
-cleanup:
-       free(hex);
        free(url);
-       return ret;
+       return tmp;
 }
 
 static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        unsigned char *sha1, const char *base_url)
 {
        struct packed_git *new_pack;
+       char *tmp_idx = NULL;
+       int ret;
 
-       if (fetch_pack_index(sha1, base_url))
+       if (has_pack_index(sha1)) {
+               new_pack = parse_pack_index(sha1, NULL);
+               if (!new_pack)
+                       return -1; /* parse_pack_index() already issued error message */
+               goto add_pack;
+       }
+
+       tmp_idx = fetch_pack_index(sha1, base_url);
+       if (!tmp_idx)
                return -1;
 
-       new_pack = parse_pack_index(sha1);
-       if (!new_pack)
+       new_pack = parse_pack_index(sha1, tmp_idx);
+       if (!new_pack) {
+               unlink(tmp_idx);
+               free(tmp_idx);
+
                return -1; /* parse_pack_index() already issued error message */
+       }
+
+       ret = verify_pack_index(new_pack);
+       if (!ret) {
+               close_pack_index(new_pack);
+               ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1));
+       }
+       free(tmp_idx);
+       if (ret)
+               return -1;
+
+add_pack:
        new_pack->next = *packs_head;
        *packs_head = new_pack;
        return 0;
@@ -1000,37 +1039,62 @@ void release_http_pack_request(struct http_pack_request *preq)
 
 int finish_http_pack_request(struct http_pack_request *preq)
 {
-       int ret;
        struct packed_git **lst;
+       struct packed_git *p = preq->target;
+       char *tmp_idx;
+       struct child_process ip;
+       const char *ip_argv[8];
 
-       preq->target->pack_size = ftell(preq->packfile);
-
-       if (preq->packfile != NULL) {
-               fclose(preq->packfile);
-               preq->packfile = NULL;
-               preq->slot->local = NULL;
-       }
+       close_pack_index(p);
 
-       ret = move_temp_to_file(preq->tmpfile, preq->filename);
-       if (ret)
-               return ret;
+       fclose(preq->packfile);
+       preq->packfile = NULL;
+       preq->slot->local = NULL;
 
        lst = preq->lst;
-       while (*lst != preq->target)
+       while (*lst != p)
                lst = &((*lst)->next);
        *lst = (*lst)->next;
 
-       if (verify_pack(preq->target))
+       tmp_idx = xstrdup(preq->tmpfile);
+       strcpy(tmp_idx + strlen(tmp_idx) - strlen(".pack.temp"),
+              ".idx.temp");
+
+       ip_argv[0] = "index-pack";
+       ip_argv[1] = "-o";
+       ip_argv[2] = tmp_idx;
+       ip_argv[3] = preq->tmpfile;
+       ip_argv[4] = NULL;
+
+       memset(&ip, 0, sizeof(ip));
+       ip.argv = ip_argv;
+       ip.git_cmd = 1;
+       ip.no_stdin = 1;
+       ip.no_stdout = 1;
+
+       if (run_command(&ip)) {
+               unlink(preq->tmpfile);
+               unlink(tmp_idx);
+               free(tmp_idx);
+               return -1;
+       }
+
+       unlink(sha1_pack_index_name(p->sha1));
+
+       if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1))
+        || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
+               free(tmp_idx);
                return -1;
-       install_packed_git(preq->target);
+       }
 
+       install_packed_git(p);
+       free(tmp_idx);
        return 0;
 }
 
 struct http_pack_request *new_http_pack_request(
        struct packed_git *target, const char *base_url)
 {
-       char *filename;
        long prev_posn = 0;
        char range[RANGE_HEADER_SIZE];
        struct strbuf buf = STRBUF_INIT;
@@ -1045,9 +1109,8 @@ struct http_pack_request *new_http_pack_request(
                sha1_to_hex(target->sha1));
        preq->url = strbuf_detach(&buf, NULL);
 
-       filename = sha1_pack_name(target->sha1);
-       snprintf(preq->filename, sizeof(preq->filename), "%s", filename);
-       snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp", filename);
+       snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
+               sha1_pack_name(target->sha1));
        preq->packfile = fopen(preq->tmpfile, "a");
        if (!preq->packfile) {
                error("Unable to open local file %s for pack",
@@ -1082,7 +1145,6 @@ struct http_pack_request *new_http_pack_request(
        return preq;
 
 abort:
-       free(filename);
        free(preq->url);
        free(preq);
        return NULL;
@@ -1137,7 +1199,6 @@ struct http_object_request *new_http_object_request(const char *base_url,
        freq->localfile = -1;
 
        filename = sha1_file_name(sha1);
-       snprintf(freq->filename, sizeof(freq->filename), "%s", filename);
        snprintf(freq->tmpfile, sizeof(freq->tmpfile),
                 "%s.temp", filename);
 
@@ -1166,8 +1227,8 @@ struct http_object_request *new_http_object_request(const char *base_url,
        }
 
        if (freq->localfile < 0) {
-               error("Couldn't create temporary file %s for %s: %s",
-                     freq->tmpfile, freq->filename, strerror(errno));
+               error("Couldn't create temporary file %s: %s",
+                     freq->tmpfile, strerror(errno));
                goto abort;
        }
 
@@ -1214,8 +1275,8 @@ struct http_object_request *new_http_object_request(const char *base_url,
                        prev_posn = 0;
                        lseek(freq->localfile, 0, SEEK_SET);
                        if (ftruncate(freq->localfile, 0) < 0) {
-                               error("Couldn't truncate temporary file %s for %s: %s",
-                                         freq->tmpfile, freq->filename, strerror(errno));
+                               error("Couldn't truncate temporary file %s: %s",
+                                         freq->tmpfile, strerror(errno));
                                goto abort;
                        }
                }
@@ -1291,7 +1352,7 @@ int finish_http_object_request(struct http_object_request *freq)
                return -1;
        }
        freq->rename =
-               move_temp_to_file(freq->tmpfile, freq->filename);
+               move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1));
 
        return freq->rename;
 }
diff --git a/http.h b/http.h
index 5c9441c10ce708be426afe7424d63dcbb68a49e2..a0b59015948c3b9736dd6c09fd9137f7ecd4f59a 100644 (file)
--- a/http.h
+++ b/http.h
@@ -117,6 +117,7 @@ extern void append_remote_object_url(struct strbuf *buf, const char *url,
                                     int only_two_digit_prefix);
 extern char *get_remote_object_url(const char *url, const char *hex,
                                   int only_two_digit_prefix);
+extern void end_url_with_slash(struct strbuf *buf, const char *url);
 
 /* Options for http_request_*() */
 #define HTTP_NO_CACHE          1
@@ -126,6 +127,8 @@ extern char *get_remote_object_url(const char *url, const char *hex,
 #define HTTP_MISSING_TARGET    1
 #define HTTP_ERROR             2
 #define HTTP_START_FAILED      3
+#define HTTP_REAUTH    4
+#define HTTP_NOAUTH    5
 
 /*
  * Requests an url and stores the result in a strbuf.
@@ -152,7 +155,6 @@ struct http_pack_request
        struct packed_git *target;
        struct packed_git **lst;
        FILE *packfile;
-       char filename[PATH_MAX];
        char tmpfile[PATH_MAX];
        struct curl_slist *range_header;
        struct active_request_slot *slot;
@@ -167,7 +169,6 @@ extern void release_http_pack_request(struct http_pack_request *preq);
 struct http_object_request
 {
        char *url;
-       char filename[PATH_MAX];
        char tmpfile[PATH_MAX];
        int localfile;
        CURLcode curl_result;
index aeb2985b831c982f10c3905f5053136520fcc4fe..9d0097ca02960460ff3a104f1739982fee453987 100644 (file)
@@ -1226,9 +1226,6 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
                        fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host);
                        goto bail;
                }
-               if (!imap->buf.sock.ssl)
-                       imap_warn("*** IMAP Warning *** Password is being "
-                                 "sent in the clear\n");
 
                if (srvc->auth_method) {
                        struct imap_cmd_cb cb;
@@ -1253,6 +1250,9 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
                                goto bail;
                        }
                } else {
+                       if (!imap->buf.sock.ssl)
+                               imap_warn("*** IMAP Warning *** Password is being "
+                                         "sent in the clear\n");
                        if (imap_exec(ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass) != RESP_OK) {
                                fprintf(stderr, "IMAP error: LOGIN failed\n");
                                goto bail;
@@ -1431,8 +1431,14 @@ static int count_messages(struct msg_data *msg)
 
        while (1) {
                if (!prefixcmp(p, "From ")) {
+                       p = strstr(p+5, "\nFrom: ");
+                       if (!p) break;
+                       p = strstr(p+7, "\nDate: ");
+                       if (!p) break;
+                       p = strstr(p+7, "\nSubject: ");
+                       if (!p) break;
+                       p += 10;
                        count++;
-                       p += 5;
                }
                p = strstr(p+5, "\nFrom ");
                if (!p)
index 82c7742e41f4645e7d6086bb277437a84ff4f03b..f9b3d854a921ab6fa3eed6f4dbf01af1a8657602 100644 (file)
@@ -15,7 +15,7 @@ struct ll_merge_driver;
 typedef int (*ll_merge_fn)(const struct ll_merge_driver *,
                           mmbuffer_t *result,
                           const char *path,
-                          mmfile_t *orig,
+                          mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
                           int flag,
@@ -36,7 +36,7 @@ struct ll_merge_driver {
 static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
                           mmbuffer_t *result,
                           const char *path_unused,
-                          mmfile_t *orig,
+                          mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
                           int flag, int marker_size)
@@ -57,7 +57,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
 static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        mmbuffer_t *result,
                        const char *path,
-                       mmfile_t *orig,
+                       mmfile_t *orig, const char *orig_name,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
                        int flag, int marker_size)
@@ -71,7 +71,8 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        path, name1, name2);
                return ll_binary_merge(drv_unused, result,
                                       path,
-                                      orig, src1, name1,
+                                      orig, orig_name,
+                                      src1, name1,
                                       src2, name2,
                                       flag, marker_size);
        }
@@ -83,13 +84,16 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                xmp.style = git_xmerge_style;
        if (marker_size > 0)
                xmp.marker_size = marker_size;
-       return xdl_merge(orig, src1, name1, src2, name2, &xmp, result);
+       xmp.ancestor = orig_name;
+       xmp.file1 = name1;
+       xmp.file2 = name2;
+       return xdl_merge(orig, src1, src2, &xmp, result);
 }
 
 static int ll_union_merge(const struct ll_merge_driver *drv_unused,
                          mmbuffer_t *result,
                          const char *path_unused,
-                         mmfile_t *orig,
+                         mmfile_t *orig, const char *orig_name,
                          mmfile_t *src1, const char *name1,
                          mmfile_t *src2, const char *name2,
                          int flag, int marker_size)
@@ -97,7 +101,7 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,
        /* Use union favor */
        flag = (flag & 1) | (XDL_MERGE_FAVOR_UNION << 1);
        return ll_xdl_merge(drv_unused, result, path_unused,
-                           orig, src1, NULL, src2, NULL,
+                           orig, NULL, src1, NULL, src2, NULL,
                            flag, marker_size);
        return 0;
 }
@@ -128,7 +132,7 @@ static void create_temp(mmfile_t *src, char *path)
 static int ll_ext_merge(const struct ll_merge_driver *fn,
                        mmbuffer_t *result,
                        const char *path,
-                       mmfile_t *orig,
+                       mmfile_t *orig, const char *orig_name,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
                        int flag, int marker_size)
@@ -319,7 +323,7 @@ static int git_path_check_merge(const char *path, struct git_attr_check check[2]
 
 int ll_merge(mmbuffer_t *result_buf,
             const char *path,
-            mmfile_t *ancestor,
+            mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
             int flag)
@@ -341,7 +345,7 @@ int ll_merge(mmbuffer_t *result_buf,
        driver = find_ll_merge_driver(ll_driver_name);
        if (virtual_ancestor && driver->recursive)
                driver = find_ll_merge_driver(driver->recursive);
-       return driver->fn(driver, result_buf, path, ancestor,
+       return driver->fn(driver, result_buf, path, ancestor, ancestor_label,
                          ours, our_label, theirs, their_label,
                          flag, marker_size);
 }
index 57889227b1782d3792be2046fbb54bca67b779de..57754cc8ca7b378a86b168a4fd6299fa3dfba045 100644 (file)
@@ -7,7 +7,7 @@
 
 int ll_merge(mmbuffer_t *result_buf,
             const char *path,
-            mmfile_t *ancestor,
+            mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
             int flag);
index fd34d76e1516b2c944778a11a5670d382f245873..db4d0d50d32d8852d1cb5173125e4173c3badb49 100644 (file)
@@ -30,7 +30,13 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
        int merge_status;
        mmbuffer_t res;
 
-       merge_status = ll_merge(&res, path, base,
+       /*
+        * This function is only used by cmd_merge_tree, which
+        * does not respect the merge.conflictstyle option.
+        * There is no need to worry about a label for the
+        * common ancestor.
+        */
+       merge_status = ll_merge(&res, path, base, NULL,
                                our, ".our", their, ".their", 0);
        if (merge_status < 0)
                return NULL;
@@ -60,7 +66,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
        xdemitcb_t ecb;
 
        memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = 0;
        memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
        xecfg.flags = XDL_EMIT_COMMON;
index 87232b899d8ab12c2f3c6704a9a1ca12d4a9f286..206c1036359ce7b1fc5a1f5734b2d0bc2a760d90 100644 (file)
@@ -608,7 +608,7 @@ static int merge_3way(struct merge_options *o,
                      const char *branch2)
 {
        mmfile_t orig, src1, src2;
-       char *name1, *name2;
+       char *base_name, *name1, *name2;
        int merge_status;
        int favor;
 
@@ -628,10 +628,15 @@ static int merge_3way(struct merge_options *o,
                }
        }
 
-       if (strcmp(a->path, b->path)) {
+       if (strcmp(a->path, b->path) ||
+           (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
+               base_name = o->ancestor == NULL ? NULL :
+                       xstrdup(mkpath("%s:%s", o->ancestor, one->path));
                name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
                name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
        } else {
+               base_name = o->ancestor == NULL ? NULL :
+                       xstrdup(mkpath("%s", o->ancestor));
                name1 = xstrdup(mkpath("%s", branch1));
                name2 = xstrdup(mkpath("%s", branch2));
        }
@@ -640,7 +645,7 @@ static int merge_3way(struct merge_options *o,
        read_mmblob(&src1, a->sha1);
        read_mmblob(&src2, b->sha1);
 
-       merge_status = ll_merge(result_buf, a->path, &orig,
+       merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2,
                                (!!o->call_depth) | (favor << 1));
 
@@ -1342,6 +1347,7 @@ int merge_recursive(struct merge_options *o,
        if (!o->call_depth)
                read_cache();
 
+       o->ancestor = "merged common ancestors";
        clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
                            &mrtree);
 
index be8410ad1803bc10e5dbf74f39eecdfed53469b1..d1192f56d797a1664f5bfb5028d52ad679928e23 100644 (file)
@@ -4,6 +4,7 @@
 #include "string-list.h"
 
 struct merge_options {
+       const char *ancestor;
        const char *branch1;
        const char *branch2;
        enum {
diff --git a/notes.h b/notes.h
index ee65bd1a2430d4af53f03fd2cc9faa916863408c..9f59277c516f7ac78bcc66f91a7d7013b2a77f65 100644 (file)
--- a/notes.h
+++ b/notes.h
@@ -212,7 +212,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,
 struct string_list;
 
 struct display_notes_opt {
-       int suppress_default_notes:1;
+       unsigned int suppress_default_notes:1;
        struct string_list *extra_notes_refs;
 };
 
index 3ca92c4c4def46af10556dbe9b3f48774b9a4a35..277b3ddba7dc5387cd97cb35c23d3358727898be 100644 (file)
--- a/object.c
+++ b/object.c
@@ -252,10 +252,10 @@ void add_object_array_with_mode(struct object *obj, const char *name, struct obj
 
 void object_array_remove_duplicates(struct object_array *array)
 {
-       int ref, src, dst;
+       unsigned int ref, src, dst;
        struct object_array_entry *objects = array->objects;
 
-       for (ref = 0; ref < array->nr - 1; ref++) {
+       for (ref = 0; ref + 1 < array->nr; ref++) {
                for (src = ref + 1, dst = src;
                     src < array->nr;
                     src++) {
index 166ca703c10face0d4961da6ceee7a149ebcfac4..395fb9527a3bc6dd8ca648233911a1c35604440d 100644 (file)
@@ -133,14 +133,13 @@ static int verify_packfile(struct packed_git *p,
        return err;
 }
 
-int verify_pack(struct packed_git *p)
+int verify_pack_index(struct packed_git *p)
 {
        off_t index_size;
        const unsigned char *index_base;
        git_SHA_CTX ctx;
        unsigned char sha1[20];
        int err = 0;
-       struct pack_window *w_curs = NULL;
 
        if (open_pack_index(p))
                return error("packfile %s index not opened", p->pack_name);
@@ -154,8 +153,18 @@ int verify_pack(struct packed_git *p)
        if (hashcmp(sha1, index_base + index_size - 20))
                err = error("Packfile index for %s SHA1 mismatch",
                            p->pack_name);
+       return err;
+}
+
+int verify_pack(struct packed_git *p)
+{
+       int err = 0;
+       struct pack_window *w_curs = NULL;
+
+       err |= verify_pack_index(p);
+       if (!p->index_data)
+               return -1;
 
-       /* Verify pack file */
        err |= verify_packfile(p, &w_curs);
        unuse_pack(&w_curs);
 
diff --git a/pack.h b/pack.h
index d268c014c9eb7040bd65125b13d68edce670274b..bb275762b7eb6f473f333ae40780821e383db20b 100644 (file)
--- a/pack.h
+++ b/pack.h
@@ -57,6 +57,7 @@ struct pack_idx_entry {
 
 extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
 extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
+extern int verify_pack_index(struct packed_git *);
 extern int verify_pack(struct packed_git *);
 extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
 extern char *index_pack_lockfile(int fd);
index c83035d013d3f50e9367f2b07d49cf17a1e22ff6..8546d8526f311e2a2703c258a4da3f02f8650df4 100644 (file)
@@ -659,3 +659,18 @@ int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
        *target = unset ? 2 : 1;
        return 0;
 }
+
+int parse_options_concat(struct option *dst, size_t dst_size, struct option *src)
+{
+       int i, j;
+
+       for (i = 0; i < dst_size; i++)
+               if (dst[i].type == OPTION_END)
+                       break;
+       for (j = 0; i < dst_size; i++, j++) {
+               dst[i] = src[j];
+               if (src[j].type == OPTION_END)
+                       return 0;
+       }
+       return -1;
+}
index 9429f7e36112b7b9cf52d4b3b68b007938396322..7581e931da13151473739036a89d9d19303eb18b 100644 (file)
@@ -187,6 +187,7 @@ extern int parse_options_step(struct parse_opt_ctx_t *ctx,
 
 extern int parse_options_end(struct parse_opt_ctx_t *ctx);
 
+extern int parse_options_concat(struct option *dst, size_t, struct option *src);
 
 /*----- some often used options -----*/
 extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
index 6ba3da89b7d29ef35a6ac9215b4f3e0abe7a582f..2777d30224618fb0ec823961c3c35ede1ac4e2e5 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -716,7 +716,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                if (add_again(sb, &c->abbrev_commit_hash))
                        return 1;
                strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
-                                                    DEFAULT_ABBREV));
+                                                    c->pretty_ctx->abbrev));
                c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
                return 1;
        case 'T':               /* tree hash */
@@ -726,7 +726,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                if (add_again(sb, &c->abbrev_tree_hash))
                        return 1;
                strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
-                                                    DEFAULT_ABBREV));
+                                                    c->pretty_ctx->abbrev));
                c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
                return 1;
        case 'P':               /* parent hashes */
@@ -743,7 +743,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                        if (p != commit->parents)
                                strbuf_addch(sb, ' ');
                        strbuf_addstr(sb, find_unique_abbrev(
-                                       p->item->object.sha1, DEFAULT_ABBREV));
+                                       p->item->object.sha1,
+                                       c->pretty_ctx->abbrev));
                }
                c->abbrev_parent_hashes.len = sb->len -
                                              c->abbrev_parent_hashes.off;
@@ -775,10 +776,13 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                }
                return 0;       /* unknown %g placeholder */
        case 'N':
-               format_display_notes(commit->object.sha1, sb,
-                           git_log_output_encoding ? git_log_output_encoding
-                                                   : git_commit_encoding, 0);
-               return 1;
+               if (c->pretty_ctx->show_notes) {
+                       format_display_notes(commit->object.sha1, sb,
+                                   git_log_output_encoding ? git_log_output_encoding
+                                                           : git_commit_encoding, 0);
+                       return 1;
+               }
+               return 0;
        }
 
        /* For the rest we have to parse the commit header. */
@@ -855,6 +859,35 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        return consumed + 1;
 }
 
+static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
+                                  void *context)
+{
+       struct userformat_want *w = context;
+
+       if (*placeholder == '+' || *placeholder == '-')
+               placeholder++;
+
+       switch (*placeholder) {
+       case 'N':
+               w->notes = 1;
+               break;
+       }
+       return 0;
+}
+
+void userformat_find_requirements(const char *fmt, struct userformat_want *w)
+{
+       struct strbuf dummy = STRBUF_INIT;
+
+       if (!fmt) {
+               if (!user_format)
+                       return;
+               fmt = user_format;
+       }
+       strbuf_expand(&dummy, user_format, userformat_want_item, w);
+       strbuf_release(&dummy);
+}
+
 void format_commit_message(const struct commit *commit,
                           const char *format, struct strbuf *sb,
                           const struct pretty_print_context *pretty_ctx)
diff --git a/refs.c b/refs.c
index 0f24c8d5d9fa897c0b72c529c9fd2ccbcc7bd4d9..d3db15a76cc46f6f6a31d4448816c09e6c48e543 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1276,6 +1276,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
        if (log_all_ref_updates &&
            (!prefixcmp(ref_name, "refs/heads/") ||
             !prefixcmp(ref_name, "refs/remotes/") ||
+            !prefixcmp(ref_name, "refs/notes/") ||
             !strcmp(ref_name, "HEAD"))) {
                if (safe_create_leading_directories(log_file) < 0)
                        return error("unable to create directory for %s",
index b76bfcb3d3cdbbee2e3279a6696c7d6b526176d7..24fbb9a9b972c1078b3688b2d0683c9704e09ee6 100644 (file)
@@ -9,7 +9,7 @@
 #include "sideband.h"
 
 static struct remote *remote;
-static const char *url;
+static const char *url; /* always ends with a trailing slash */
 
 struct options {
        int verbosity;
@@ -101,7 +101,7 @@ static struct discovery* discover_refs(const char *service)
                return last;
        free_discovery(last);
 
-       strbuf_addf(&buffer, "%s/info/refs", url);
+       strbuf_addf(&buffer, "%sinfo/refs", url);
        if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) {
                is_http = 1;
                if (!strchr(url, '?'))
@@ -120,7 +120,7 @@ static struct discovery* discover_refs(const char *service)
                strbuf_reset(&buffer);
 
                proto_git_candidate = 0;
-               strbuf_addf(&buffer, "%s/info/refs", url);
+               strbuf_addf(&buffer, "%sinfo/refs", url);
                refs_url = strbuf_detach(&buffer, NULL);
 
                http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
@@ -132,6 +132,8 @@ static struct discovery* discover_refs(const char *service)
        case HTTP_MISSING_TARGET:
                die("%s not found: did you run git update-server-info on the"
                    " server?", refs_url);
+       case HTTP_NOAUTH:
+               die("Authentication failed");
        default:
                http_error(refs_url, http_ret);
                die("HTTP request failed");
@@ -509,7 +511,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
        rpc->out = client.out;
        strbuf_init(&rpc->result, 0);
 
-       strbuf_addf(&buf, "%s/%s", url, svc);
+       strbuf_addf(&buf, "%s%s", url, svc);
        rpc->service_url = strbuf_detach(&buf, NULL);
 
        strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
@@ -798,11 +800,13 @@ int main(int argc, const char **argv)
        remote = remote_get(argv[1]);
 
        if (argc > 2) {
-               url = argv[2];
+               end_url_with_slash(&buf, argv[2]);
        } else {
-               url = remote->url[0];
+               end_url_with_slash(&buf, remote->url[0]);
        }
 
+       url = strbuf_detach(&buf, NULL);
+
        http_init(remote);
 
        do {
index c70181cdc621b27ed02aba17b3e4f7ab64518e9f..26ce56046dd14fec4ae59c7e7df3c2072178c51d 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -476,7 +476,7 @@ static void read_config(void)
        unsigned char sha1[20];
        const char *head_ref;
        int flag;
-       if (default_remote_name) // did this already
+       if (default_remote_name) /* did this already */
                return;
        default_remote_name = xstrdup("origin");
        current_branch = NULL;
index a59f74f76c293efa783103eaf3d167c97b3768ea..f221bed1e97a0f1b41d1845edac270a109e3a4dd 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -319,7 +319,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
                if (!mmfile[i].ptr && !mmfile[i].size)
                        mmfile[i].ptr = xstrdup("");
        }
-       ll_merge(&result, path, &mmfile[0],
+       ll_merge(&result, path, &mmfile[0], NULL,
                 &mmfile[1], "ours",
                 &mmfile[2], "theirs", 0);
        for (i = 0; i < 3; i++)
@@ -376,7 +376,7 @@ static int merge(const char *name, const char *path)
                ret = 1;
                goto out;
        }
-       ret = ll_merge(&result, path, &base, &cur, "", &other, "", 0);
+       ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", 0);
        if (!ret) {
                FILE *f = fopen(path, "w");
                if (!f)
index c8d53795ec3ae9b8b0a73b3d6900c1a1f212d2c2..c7793f50fbe0a43495c2b2d36a47c0b5aac37483 100644 (file)
@@ -342,8 +342,6 @@ fail_pipe:
        else if (cmd->out > 1)
                fhout = dup(cmd->out);
 
-       if (cmd->dir)
-               die("chdir in start_command() not implemented");
        if (cmd->env)
                env = make_augmented_environ(cmd->env);
 
@@ -353,7 +351,7 @@ fail_pipe:
                cmd->argv = prepare_shell_cmd(cmd->argv);
        }
 
-       cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env,
+       cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
                                  fhin, fhout, fherr);
        failed_errno = errno;
        if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
@@ -385,6 +383,8 @@ fail_pipe:
                        close(cmd->out);
                if (need_err)
                        close_pair(fderr);
+               else if (cmd->err)
+                       close(cmd->err);
                errno = failed_errno;
                return -1;
        }
diff --git a/setup.c b/setup.c
index 5716d90b57574d045114f4aaad1bdf36fd79ed89..0e4cfe603f1afe515365c9daf1ad8406de8e7fa8 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -519,6 +519,12 @@ int check_repository_format(void)
        return check_repository_format_gently(NULL);
 }
 
+/*
+ * Returns the "prefix", a path to the current working directory
+ * relative to the work tree root, or NULL, if the current working
+ * directory is not a strict subdirectory of the work tree root. The
+ * prefix always ends with a '/' character.
+ */
 const char *setup_git_directory(void)
 {
        const char *retval = setup_git_directory_gently(NULL);
index a08a9d08808bdb2f4a138d7e6f602b61fc093c1b..72de38909ef6b05f0aa709b78fd803c632a02044 100644 (file)
@@ -102,20 +102,22 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
  */
 char *sha1_file_name(const unsigned char *sha1)
 {
-       static char *name, *base;
+       static char buf[PATH_MAX];
+       const char *objdir;
+       int len;
 
-       if (!base) {
-               const char *sha1_file_directory = get_object_directory();
-               int len = strlen(sha1_file_directory);
-               base = xmalloc(len + 60);
-               memcpy(base, sha1_file_directory, len);
-               memset(base+len, 0, 60);
-               base[len] = '/';
-               base[len+3] = '/';
-               name = base + len + 1;
-       }
-       fill_sha1_path(name, sha1);
-       return base;
+       objdir = get_object_directory();
+       len = strlen(objdir);
+
+       /* '/' + sha1(2) + '/' + sha1(38) + '\0' */
+       if (len + 43 > PATH_MAX)
+               die("insanely long object directory %s", objdir);
+       memcpy(buf, objdir, len);
+       buf[len] = '/';
+       buf[len+3] = '/';
+       buf[len+42] = '\0';
+       fill_sha1_path(buf + len + 1, sha1);
+       return buf;
 }
 
 static char *sha1_get_pack_name(const unsigned char *sha1,
@@ -599,6 +601,14 @@ void unuse_pack(struct pack_window **w_cursor)
        }
 }
 
+void close_pack_index(struct packed_git *p)
+{
+       if (p->index_data) {
+               munmap((void *)p->index_data, p->index_size);
+               p->index_data = NULL;
+       }
+}
+
 /*
  * This is used by git-repack in case a newly created pack happens to
  * contain the same set of objects as an existing one.  In that case
@@ -620,8 +630,7 @@ void free_pack_by_name(const char *pack_name)
                        close_pack_windows(p);
                        if (p->pack_fd != -1)
                                close(p->pack_fd);
-                       if (p->index_data)
-                               munmap((void *)p->index_data, p->index_size);
+                       close_pack_index(p);
                        free(p->bad_object_sha1);
                        *pp = p->next;
                        free(p);
@@ -831,9 +840,8 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
        return p;
 }
 
-struct packed_git *parse_pack_index(unsigned char *sha1)
+struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
 {
-       const char *idx_path = sha1_pack_index_name(sha1);
        const char *path = sha1_pack_name(sha1);
        struct packed_git *p = alloc_packed_git(strlen(path) + 1);
 
@@ -2271,7 +2279,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
 }
 
 static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
-                             void *buf, unsigned long len, time_t mtime)
+                             const void *buf, unsigned long len, time_t mtime)
 {
        int fd, ret;
        unsigned char compressed[4096];
@@ -2307,7 +2315,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        git_SHA1_Update(&c, hdr, hdrlen);
 
        /* Then the data itself.. */
-       stream.next_in = buf;
+       stream.next_in = (void *)buf;
        stream.avail_in = len;
        do {
                unsigned char *in0 = stream.next_in;
@@ -2342,7 +2350,7 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        return move_temp_to_file(tmpfile, filename);
 }
 
-int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 {
        unsigned char sha1[20];
        char hdr[32];
@@ -2448,6 +2456,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
                else
                        ret = -1;
                strbuf_release(&sbuf);
+       } else if (!size) {
+               ret = index_mem(sha1, NULL, size, write_object, type, path);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                if (size == read_in_full(fd, buf, size))
@@ -2456,12 +2466,11 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
                else
                        ret = error("short read %s", strerror(errno));
                free(buf);
-       } else if (size) {
+       } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
                ret = index_mem(sha1, buf, size, write_object, type, path);
                munmap(buf, size);
-       } else
-               ret = index_mem(sha1, NULL, size, write_object, type, path);
+       }
        close(fd);
        return ret;
 }
index bc02cc29ef0d5f640ab390614def995f30fe4691..de4f86fb970e15491f44dfe38b7d7d6fdc3be9ad 100644 (file)
@@ -12,6 +12,7 @@ struct shortlog {
        int in1;
        int in2;
        int user_format;
+       int abbrev;
 
        char *common_repo_prefix;
        int email;
index 1ac536e638dbbc02deb2d4e4a607cc52f7f7c108..c9ad7fcd49669b0dff481d9ab857bf70d8a51bca 100644 (file)
@@ -168,12 +168,19 @@ void sort_string_list(struct string_list *list)
        qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
 }
 
-int unsorted_string_list_has_string(struct string_list *list, const char *string)
+struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
+                                                    const char *string)
 {
        int i;
        for (i = 0; i < list->nr; i++)
                if (!strcmp(string, list->items[i].string))
-                       return 1;
-       return 0;
+                       return list->items + i;
+       return NULL;
+}
+
+int unsorted_string_list_has_string(struct string_list *list,
+                                   const char *string)
+{
+       return unsorted_string_list_lookup(list, string) != NULL;
 }
 
index 6569cf607b18b84f39ebee613471f270e42cfbdc..63b69c8d75ee33120a65a23598ddf93e84831bdd 100644 (file)
@@ -38,5 +38,6 @@ struct string_list_item *string_list_lookup(const char *string, struct string_li
 struct string_list_item *string_list_append(const char *string, struct string_list *list);
 void sort_string_list(struct string_list *list);
 int unsorted_string_list_has_string(struct string_list *list, const char *string);
-
+struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
+                                                    const char *string);
 #endif /* STRING_LIST_H */
index b3b8bc147909f81be6a387318ad0601dae50460f..676d48fb33119f393befcaf8998ad38741366525 100644 (file)
@@ -12,8 +12,15 @@ static int add_submodule_odb(const char *path)
        struct strbuf objects_directory = STRBUF_INIT;
        struct alternate_object_database *alt_odb;
        int ret = 0;
+       const char *git_dir;
 
-       strbuf_addf(&objects_directory, "%s/.git/objects/", path);
+       strbuf_addf(&objects_directory, "%s/.git", path);
+       git_dir = read_gitfile_gently(objects_directory.buf);
+       if (git_dir) {
+               strbuf_reset(&objects_directory);
+               strbuf_addstr(&objects_directory, git_dir);
+       }
+       strbuf_addstr(&objects_directory, "/objects/");
        if (!is_directory(objects_directory.buf)) {
                ret = -1;
                goto done;
@@ -132,7 +139,6 @@ void show_submodule_summary(FILE *f, const char *path,
 
 unsigned is_submodule_modified(const char *path, int ignore_untracked)
 {
-       int i;
        ssize_t len;
        struct child_process cp;
        const char *argv[] = {
@@ -141,16 +147,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
                NULL,
                NULL,
        };
-       const char *env[LOCAL_REPO_ENV_SIZE + 3];
        struct strbuf buf = STRBUF_INIT;
        unsigned dirty_submodule = 0;
        const char *line, *next_line;
+       const char *git_dir;
 
-       for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
-               env[i] = local_repo_env[i];
-
-       strbuf_addf(&buf, "%s/.git/", path);
-       if (!is_directory(buf.buf)) {
+       strbuf_addf(&buf, "%s/.git", path);
+       git_dir = read_gitfile_gently(buf.buf);
+       if (!git_dir)
+               git_dir = buf.buf;
+       if (!is_directory(git_dir)) {
                strbuf_release(&buf);
                /* The submodule is not checked out, so it is not modified */
                return 0;
@@ -158,21 +164,16 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        }
        strbuf_reset(&buf);
 
-       strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
-       env[i++] = strbuf_detach(&buf, NULL);
-       strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
-       env[i++] = strbuf_detach(&buf, NULL);
-       env[i] = NULL;
-
        if (ignore_untracked)
                argv[2] = "-uno";
 
        memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
-       cp.env = env;
+       cp.env = local_repo_env;
        cp.git_cmd = 1;
        cp.no_stdin = 1;
        cp.out = -1;
+       cp.dir = path;
        if (start_command(&cp))
                die("Could not run git status --porcelain");
 
@@ -201,8 +202,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        if (finish_command(&cp))
                die("git status --porcelain failed");
 
-       for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
-               free((char *)env[i]);
        strbuf_release(&buf);
        return dirty_submodule;
 }
index dcd3ebb5f2dcdbf15ca0e4a043b45cd2fc36cbb5..0e4e8d8862c96383a6f6f22a1b6bb01044925620 100644 (file)
--- a/t/README
+++ b/t/README
@@ -84,6 +84,12 @@ appropriately before running "make".
        implied by other options like --valgrind and
        GIT_TEST_INSTALLED.
 
+--root=<directory>::
+       Create "trash" directories used to store all temporary data during
+       testing under <directory>, instead of the t/ directory.
+       Using this option with a RAM-based filesystem (such as tmpfs)
+       can massively speed up the test suite.
+
 You can also set the GIT_TEST_INSTALLED environment variable to
 the bindir of an existing git installation to test that installation.
 You still need to have built this git sandbox, from which various
diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh
new file mode 100644 (file)
index 0000000..985d517
--- /dev/null
@@ -0,0 +1,127 @@
+: included from 6002 and others
+
+[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
+
+:> sed.script
+
+# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
+tag()
+{
+       _tag=$1
+       [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
+       cat .git/refs/tags/$_tag
+}
+
+# Generate a commit using the text specified to make it unique and the tree
+# named by the tag specified.
+unique_commit()
+{
+       _text=$1
+        _tree=$2
+       shift 2
+       echo $_text | git commit-tree $(tag $_tree) "$@"
+}
+
+# Save the output of a command into the tag specified. Prepend
+# a substitution script for the tag onto the front of sed.script
+save_tag()
+{
+       _tag=$1
+       [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
+       shift 1
+       "$@" >.git/refs/tags/$_tag
+
+        echo "s/$(tag $_tag)/$_tag/g" > sed.script.tmp
+       cat sed.script >> sed.script.tmp
+       rm sed.script
+       mv sed.script.tmp sed.script
+}
+
+# Replace unhelpful sha1 hashses with their symbolic equivalents
+entag()
+{
+       sed -f sed.script
+}
+
+# Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
+# tag to a specified value. Restore the original value on return.
+as_author()
+{
+       _author=$1
+       shift 1
+        _save=$GIT_AUTHOR_EMAIL
+
+       GIT_AUTHOR_EMAIL="$_author"
+       export GIT_AUTHOR_EMAIL
+       "$@"
+       if test -z "$_save"
+       then
+               unset GIT_AUTHOR_EMAIL
+       else
+               GIT_AUTHOR_EMAIL="$_save"
+               export GIT_AUTHOR_EMAIL
+       fi
+}
+
+commit_date()
+{
+        _commit=$1
+       git cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
+}
+
+on_committer_date()
+{
+    _date=$1
+    shift 1
+    GIT_COMMITTER_DATE="$_date"
+    export GIT_COMMITTER_DATE
+    "$@"
+    unset GIT_COMMITTER_DATE
+}
+
+# Execute a command and suppress any error output.
+hide_error()
+{
+       "$@" 2>/dev/null
+}
+
+check_output()
+{
+       _name=$1
+       shift 1
+       if eval "$*" | entag > $_name.actual
+       then
+               diff $_name.expected $_name.actual
+       else
+               return 1;
+       fi
+}
+
+# Turn a reasonable test description into a reasonable test name.
+# All alphanums translated into -'s which are then compressed and stripped
+# from front and back.
+name_from_description()
+{
+       perl -pe '
+               s/[^A-Za-z0-9.]/-/g;
+               s/-+/-/g;
+               s/-$//;
+               s/^-//;
+               y/A-Z/a-z/;
+       '
+}
+
+
+# Execute the test described by the first argument, by eval'ing
+# command line specified in the 2nd argument. Check the status code
+# is zero and that the output matches the stream read from
+# stdin.
+test_output_expect_success()
+{
+       _description=$1
+        _test=$2
+        [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
+        _name=$(echo $_description | name_from_description)
+       cat > $_name.expected
+       test_expect_success "$_description" "check_output $_name \"$_test\""
+}
index f4ca4fc85c6b52a2ba919528284f2b668e6bd3d2..3ec9cbef2c88f65e5fb254d10cc551c6c4062c88 100755 (executable)
@@ -73,6 +73,27 @@ then
        exit 1
 fi
 
+clean=no
+test_expect_success 'tests clean up after themselves' '
+    test_when_finished clean=yes
+'
+
+cleaner=no
+test_expect_code 1 'tests clean up even after a failure' '
+    test_when_finished cleaner=yes &&
+    (exit 1)
+'
+
+if test $clean$cleaner != yesyes
+then
+       say "bug in test framework: cleanup commands do not work reliably"
+       exit 1
+fi
+
+test_expect_code 2 'failure to clean up causes the test to fail' '
+    test_when_finished "(exit 2)"
+'
+
 ################################################################
 # Basics of the basics
 
index 675773479a8c6a1791ae01eb47654f4433c30ee3..7c0a698b92696ff2bbb91e65e0a42e87f9163a1d 100755 (executable)
@@ -310,4 +310,18 @@ test_expect_success POSIXPERM 'init notices EPERM' '
        )
 '
 
+test_expect_success 'init creates a new bare directory with global --bare' '
+       rm -rf newdir &&
+       git --bare init newdir &&
+       test -d newdir/refs
+'
+
+test_expect_success 'init prefers command line to GIT_DIR' '
+       rm -rf newdir &&
+       mkdir otherdir &&
+       GIT_DIR=otherdir git --bare init newdir &&
+       test -d newdir/refs &&
+       ! test -d otherdir/refs
+'
+
 test_done
index 1c77192eb318d007689089eaf42f4f939c2f9ee4..53bd7fcc4abbf6cb7db73b43d5dde477f5115f90 100755 (executable)
@@ -20,8 +20,12 @@ test_expect_success 'setup' '
 
        mkdir -p a/b/d a/c &&
        (
+               echo "[attr]notest !test"
                echo "f test=f"
                echo "a/i test=a/i"
+               echo "onoff test -test"
+               echo "offon -test test"
+               echo "no notest"
        ) >.gitattributes &&
        (
                echo "g test=a/g" &&
@@ -30,6 +34,7 @@ test_expect_success 'setup' '
        (
                echo "h test=a/b/h" &&
                echo "d/* test=a/b/d/*"
+               echo "d/yes notest"
        ) >a/b/.gitattributes
 
 '
@@ -44,6 +49,11 @@ test_expect_success 'attribute test' '
        attr_check b/g unspecified &&
        attr_check a/b/h a/b/h &&
        attr_check a/b/d/g "a/b/d/*"
+       attr_check onoff unset
+       attr_check offon set
+       attr_check no unspecified
+       attr_check a/b/d/no "a/b/d/*"
+       attr_check a/b/d/yes unspecified
 
 '
 
@@ -58,6 +68,11 @@ a/b/g: test: a/b/g
 b/g: test: unspecified
 a/b/h: test: a/b/h
 a/b/d/g: test: a/b/d/*
+onoff: test: unset
+offon: test: set
+no: test: unspecified
+a/b/d/no: test: a/b/d/*
+a/b/d/yes: test: unspecified
 EOF
 
        sed -e "s/:.*//" < expect | git check-attr --stdin test > actual &&
index 9956e3ad625eb1d70789538ecdb55e318669bdf9..b946f8768649dd76d8a175877c63d49244e00ffb 100755 (executable)
@@ -58,14 +58,12 @@ test_expect_success 'allow missing object with --missing' '
        test_cmp tree.missing actual
 '
 
-test_expect_failure 'mktree reads ls-tree -r output (1)' '
-       git mktree <all >actual &&
-       test_cmp tree actual
+test_expect_success 'mktree refuses to read ls-tree -r output (1)' '
+       test_must_fail git mktree <all >actual
 '
 
-test_expect_failure 'mktree reads ls-tree -r output (2)' '
-       git mktree <all.withsub >actual &&
-       test_cmp tree.withsub actual
+test_expect_success 'mktree refuses to read ls-tree -r output (2)' '
+       test_must_fail git mktree <all.withsub >actual
 '
 
 test_done
index cc30be4a655cad98eac233b5da9fc585ddb5d055..055ad00f778eda1de02a418bbc602e580acdaca1 100755 (executable)
@@ -20,34 +20,23 @@ if ! setfacl -m u:root:rwx .; then
     test_done
 fi
 
-modebits () {
-       ls -l "$1" | sed -e 's|^\(..........\).*|\1|'
-}
-
 check_perms_and_acl () {
-       actual=$(modebits "$1") &&
-       case "$actual" in
-       -r--r-----*)
-               : happy
-               ;;
-       *)
-               echo "Got permission '$actual', expected '-r--r-----'"
-               false
-               ;;
-       esac &&
+       test -r "$1" &&
        getfacl "$1" > actual &&
        grep -q "user:root:rwx" actual &&
        grep -q "user:${LOGNAME}:rwx" actual &&
-       grep -q "mask::r--" actual &&
+       egrep "mask::?r--" actual > /dev/null 2>&1 &&
        grep -q "group::---" actual || false
 }
 
 dirs_to_set="./ .git/ .git/objects/ .git/objects/pack/"
 
 test_expect_success 'Setup test repo' '
+       setfacl -m d:u::rwx,d:g::---,d:o:---,d:m:rwx $dirs_to_set &&
+       setfacl -m m:rwx               $dirs_to_set &&
        setfacl -m u:root:rwx          $dirs_to_set &&
-       setfacl -d -m u:"$LOGNAME":rwx $dirs_to_set &&
-       setfacl -d -m u:root:rwx       $dirs_to_set &&
+       setfacl -m d:u:"$LOGNAME":rwx  $dirs_to_set &&
+       setfacl -m d:u:root:rwx        $dirs_to_set &&
 
        touch file.txt &&
        git add file.txt &&
index 9df301211c7f03e4a9edb0ccb9b1a7a648f97d8c..bd8b60732b06365fa22585eb8e97a3b1e64fdd05 100755 (executable)
@@ -30,6 +30,7 @@ test_rev_parse() {
 
 EMPTY_TREE=$(git write-tree)
 mkdir -p work/sub/dir || exit 1
+mkdir -p work2 || exit 1
 mv .git repo.git || exit 1
 
 say "core.worktree = relative path"
@@ -54,7 +55,9 @@ GIT_DIR=$(pwd)/repo.git
 GIT_CONFIG=$GIT_DIR/config
 git config core.worktree "$(pwd)/work"
 test_rev_parse 'outside'      false false false
-cd work || exit 1
+cd work2
+test_rev_parse 'outside2'     false false false
+cd ../work || exit 1
 test_rev_parse 'inside'       false false true ''
 cd sub/dir || exit 1
 test_rev_parse 'subdirectory' false false true sub/dir/
@@ -67,7 +70,9 @@ git config core.worktree non-existent
 GIT_WORK_TREE=work
 export GIT_WORK_TREE
 test_rev_parse 'outside'      false false false
-cd work || exit 1
+cd work2
+test_rev_parse 'outside'      false false false
+cd ../work || exit 1
 GIT_WORK_TREE=.
 test_rev_parse 'inside'       false false true ''
 cd sub/dir || exit 1
@@ -76,6 +81,7 @@ test_rev_parse 'subdirectory' false false true sub/dir/
 cd ../../.. || exit 1
 
 mv work repo.git/work
+mv work2 repo.git/work2
 
 say "GIT_WORK_TREE=absolute path, work tree below git dir"
 GIT_DIR=$(pwd)/repo.git
@@ -86,6 +92,8 @@ cd repo.git || exit 1
 test_rev_parse 'in repo.git'              false true  false
 cd objects || exit 1
 test_rev_parse 'in repo.git/objects'      false true  false
+cd ../work2 || exit 1
+test_rev_parse 'in repo.git/work2'      false true  false
 cd ../work || exit 1
 test_rev_parse 'in repo.git/work'         false true true ''
 cd sub/dir || exit 1
index 20f33436d00077b64dcc855fc263cd5d0efcca38..27e2127afeeb0dd462a686254e60be74e9dd9c28 100755 (executable)
@@ -44,8 +44,10 @@ test_expect_success 'switch from symlink to dir' '
 
 '
 
-rm -fr frotz xyzzy nitfol &&
-git checkout -f master || exit
+test_expect_success 'Remove temporary directories & switch to master' '
+       rm -fr frotz xyzzy nitfol &&
+       git checkout -f master
+'
 
 test_expect_success 'switch from dir to symlink' '
 
diff --git a/t/t2106-update-index-assume-unchanged.sh b/t/t2106-update-index-assume-unchanged.sh
new file mode 100755 (executable)
index 0000000..99d858c
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+test_description='git update-index --assume-unchanged test.
+'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' \
+       ': >file &&
+        git add file &&
+        git commit -m initial &&
+        git branch other &&
+        echo upstream >file &&
+        git add file &&
+        git commit -m upstream'
+
+test_expect_success 'do not switch branches with dirty file' \
+       'git reset --hard &&
+        git checkout other &&
+        echo dirt >file &&
+        git update-index --assume-unchanged file &&
+        test_must_fail git checkout master'
+
+test_done
index a4a0b1d6c58a7ae2762de6a907b4138238e95a48..64f32ad94dfe842746774596b88c91e873da864f 100755 (executable)
@@ -55,6 +55,15 @@ test_expect_success 'handle empty notes gracefully' '
        git notes show ; test 1 = $?
 '
 
+test_expect_success 'show non-existent notes entry with %N' '
+       for l in A B
+       do
+               echo "$l"
+       done >expect &&
+       git show -s --format='A%n%NB' >output &&
+       test_cmp expect output
+'
+
 test_expect_success 'create notes' '
        git config core.notesRef refs/notes/commits &&
        MSG=b4 git notes add &&
@@ -65,6 +74,24 @@ test_expect_success 'create notes' '
        test_must_fail git notes show HEAD^
 '
 
+test_expect_success 'show notes entry with %N' '
+       for l in A b4 B
+       do
+               echo "$l"
+       done >expect &&
+       git show -s --format='A%n%NB' >output &&
+       test_cmp expect output
+'
+
+cat >expect <<EOF
+d423f8c refs/notes/commits@{0}: notes: Notes added by 'git notes add'
+EOF
+
+test_expect_success 'create reflog entry' '
+       git reflog show refs/notes/commits >output &&
+       test_cmp expect output
+'
+
 test_expect_success 'edit existing notes' '
        MSG=b3 git notes edit &&
        test ! -f .git/NOTES_EDITMSG &&
@@ -378,6 +405,17 @@ test_expect_success 'append to existing note with "git notes append"' '
        test_cmp expect output
 '
 
+cat > expect_list << EOF
+c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75
+c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5
+4b6ad22357cc8a1296720574b8d2fbc22fab0671 bd1753200303d0a0344be813e504253b3d98e74d
+EOF
+
+test_expect_success '"git notes list" does not expand to "git notes list HEAD"' '
+       git notes list > output &&
+       test_cmp expect_list output
+'
+
 test_expect_success 'appending empty string does not change existing note' '
        git notes append -m "" &&
        git notes show > output &&
diff --git a/t/t3307-notes-man.sh b/t/t3307-notes-man.sh
new file mode 100755 (executable)
index 0000000..3269f2e
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='Examples from the git-notes man page
+
+Make sure the manual is not full of lies.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit A &&
+       test_commit B &&
+       test_commit C
+'
+
+test_expect_success 'example 1: notes to add an Acked-by line' '
+       cat <<-\EOF >expect &&
+           B
+
+       Notes:
+           Acked-by: A C Ker <acker@example.com>
+       EOF
+       git notes add -m "Acked-by: A C Ker <acker@example.com>" B &&
+       git show -s B^{commit} >log &&
+       tail -n 4 log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'example 2: binary notes' '
+       cp "$TEST_DIRECTORY"/test4012.png .
+       git checkout B &&
+       blob=$(git hash-object -w test4012.png) &&
+       git notes --ref=logo add -C "$blob" &&
+       git notes --ref=logo copy B C &&
+       git notes --ref=logo show C >actual &&
+       test_cmp test4012.png actual
+'
+
+test_done
index 19668c2c9206c5dfe63a5992bc7d011a9cdb4083..f20ea38411d0ca67709dbde0bfd1108e28c0dd71 100755 (executable)
@@ -22,12 +22,18 @@ set_fake_editor
 # | \
 # |   F - G - H                (branch1)
 # |     \
-#  \      I                    (branch2)
-#   \
-#     J - K - L - M            (no-conflict-branch)
+# |\      I                    (branch2)
+# | \
+# |   J - K - L - M            (no-conflict-branch)
+#  \
+#    N - O - P                 (no-ff-branch)
 #
 # where A, B, D and G all touch file1, and one, two, three, four all
 # touch file "conflict".
+#
+# WARNING: Modifications to the initial repository can change the SHA ID used
+# in the expect2 file for the 'stop on conflicting pick' test.
+
 
 test_expect_success 'setup' '
        test_commit A file1 &&
@@ -48,6 +54,11 @@ test_expect_success 'setup' '
        done &&
        git checkout -b no-conflict-branch A &&
        for n in J K L M
+       do
+               test_commit $n file$n
+       done &&
+       git checkout -b no-ff-branch A &&
+       for n in N O P
        do
                test_commit $n file$n
        done
@@ -113,7 +124,7 @@ cat > expect2 << EOF
 D
 =======
 G
->>>>>>> 51047de... G
+>>>>>>> 5d18e54... G
 EOF
 
 test_expect_success 'stop on conflicting pick' '
@@ -577,4 +588,30 @@ test_expect_success 'rebase -i can copy notes over a fixup' '
        test_cmp expect output
 '
 
+test_expect_success 'rebase while detaching HEAD' '
+       git symbolic-ref HEAD &&
+       grandparent=$(git rev-parse HEAD~2) &&
+       test_tick &&
+       FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
+       test $grandparent = $(git rev-parse HEAD~2) &&
+       test_must_fail git symbolic-ref HEAD
+'
+
+test_tick # Ensure that the rebased commits get a different timestamp.
+test_expect_success 'always cherry-pick with --no-ff' '
+       git checkout no-ff-branch &&
+       git tag original-no-ff-branch &&
+       git rebase -i --no-ff A &&
+       touch empty &&
+       for p in 0 1 2
+       do
+               test ! $(git rev-parse HEAD~$p) = $(git rev-parse original-no-ff-branch~$p) &&
+               git diff HEAD~$p original-no-ff-branch~$p > out &&
+               test_cmp empty out
+       done &&
+       test $(git rev-parse HEAD~3) = $(git rev-parse original-no-ff-branch~3) &&
+       git diff HEAD~3 original-no-ff-branch~3 > out &&
+       test_cmp empty out
+'
+
 test_done
diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh
new file mode 100755 (executable)
index 0000000..e17ae71
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+test_description='test cherry-picking with --ff option'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo first > file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit -m "first" &&
+       git tag first &&
+
+       git checkout -b other &&
+       echo second >> file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit -m "second" &&
+       git tag second
+'
+
+test_expect_success 'cherry-pick using --ff fast forwards' '
+       git checkout master &&
+       git reset --hard first &&
+       test_tick &&
+       git cherry-pick --ff second &&
+       test "$(git rev-parse --verify HEAD)" = "$(git rev-parse --verify second)"
+'
+
+test_expect_success 'cherry-pick not using --ff does not fast forwards' '
+       git checkout master &&
+       git reset --hard first &&
+       test_tick &&
+       git cherry-pick second &&
+       test "$(git rev-parse --verify HEAD)" != "$(git rev-parse --verify second)"
+'
+
+#
+# We setup the following graph:
+#
+#            B---C
+#           /   /
+#      first---A
+#
+# (This has been taken from t3502-cherry-pick-merge.sh)
+#
+test_expect_success 'merge setup' '
+       git checkout master &&
+       git reset --hard first &&
+       echo new line >A &&
+       git add A &&
+       test_tick &&
+       git commit -m "add line to A" A &&
+       git tag A &&
+       git checkout -b side first &&
+       echo new line >B &&
+       git add B &&
+       test_tick &&
+       git commit -m "add line to B" B &&
+       git tag B &&
+       git checkout master &&
+       git merge side &&
+       git tag C &&
+       git checkout -b new A
+'
+
+test_expect_success 'cherry-pick a non-merge with --ff and -m should fail' '
+       git reset --hard A -- &&
+       test_must_fail git cherry-pick --ff -m 1 B &&
+       git diff --exit-code A --
+'
+
+test_expect_success 'cherry pick a merge with --ff but without -m should fail' '
+       git reset --hard A -- &&
+       test_must_fail git cherry-pick --ff C &&
+       git diff --exit-code A --
+'
+
+test_expect_success 'cherry pick with --ff a merge (1)' '
+       git reset --hard A -- &&
+       git cherry-pick --ff -m 1 C &&
+       git diff --exit-code C &&
+       test "$(git rev-parse --verify HEAD)" = "$(git rev-parse --verify C)"
+'
+
+test_expect_success 'cherry pick with --ff a merge (2)' '
+       git reset --hard B -- &&
+       git cherry-pick --ff -m 2 C &&
+       git diff --exit-code C &&
+       test "$(git rev-parse --verify HEAD)" = "$(git rev-parse --verify C)"
+'
+
+test_expect_success 'cherry pick a merge relative to nonexistent parent with --ff should fail' '
+       git reset --hard B -- &&
+       test_must_fail git cherry-pick --ff -m 3 C
+'
+
+test_done
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
new file mode 100755 (executable)
index 0000000..e25cf80
--- /dev/null
@@ -0,0 +1,198 @@
+#!/bin/sh
+
+test_description='test cherry-pick and revert with conflicts
+
+  -
+  + picked: rewrites foo to c
+  + base: rewrites foo to b
+  + initial: writes foo as a, unrelated as unrelated
+
+'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       echo unrelated >unrelated &&
+       git add unrelated &&
+       test_commit initial foo a &&
+       test_commit base foo b &&
+       test_commit picked foo c &&
+       git config advice.detachedhead false
+
+'
+
+test_expect_success 'failed cherry-pick does not advance HEAD' '
+
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       head=$(git rev-parse HEAD) &&
+       test_must_fail git cherry-pick picked &&
+       newhead=$(git rev-parse HEAD) &&
+
+       test "$head" = "$newhead"
+'
+
+test_expect_success 'failed cherry-pick produces dirty index' '
+
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+
+       test_must_fail git update-index --refresh -q &&
+       test_must_fail git diff-index --exit-code HEAD
+'
+
+test_expect_success 'failed cherry-pick registers participants in index' '
+
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       {
+               git checkout base -- foo &&
+               git ls-files --stage foo &&
+               git checkout initial -- foo &&
+               git ls-files --stage foo &&
+               git checkout picked -- foo &&
+               git ls-files --stage foo
+       } > stages &&
+       sed "
+               1 s/ 0  / 1     /
+               2 s/ 0  / 2     /
+               3 s/ 0  / 3     /
+       " < stages > expected &&
+       git checkout -f initial^0 &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+       git ls-files --stage --unmerged > actual &&
+
+       test_cmp expected actual
+'
+
+test_expect_success 'failed cherry-pick describes conflict in work tree' '
+
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       =======
+       c
+       >>>>>>> objid picked
+       EOF
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'diff3 -m style' '
+
+       git config merge.conflictstyle diff3 &&
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       ||||||| parent of objid picked
+       b
+       =======
+       c
+       >>>>>>> objid picked
+       EOF
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git cherry-pick picked &&
+
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'revert also handles conflicts sanely' '
+
+       git config --unset merge.conflictstyle &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       =======
+       b
+       >>>>>>> parent of objid picked
+       EOF
+       {
+               git checkout picked -- foo &&
+               git ls-files --stage foo &&
+               git checkout initial -- foo &&
+               git ls-files --stage foo &&
+               git checkout base -- foo &&
+               git ls-files --stage foo
+       } > stages &&
+       sed "
+               1 s/ 0  / 1     /
+               2 s/ 0  / 2     /
+               3 s/ 0  / 3     /
+       " < stages > expected-stages &&
+       git checkout -f initial^0 &&
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       head=$(git rev-parse HEAD) &&
+       test_must_fail git revert picked &&
+       newhead=$(git rev-parse HEAD) &&
+       git ls-files --stage --unmerged > actual-stages &&
+
+       test "$head" = "$newhead" &&
+       test_must_fail git update-index --refresh -q &&
+       test_must_fail git diff-index --exit-code HEAD &&
+       test_cmp expected-stages actual-stages &&
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'revert conflict, diff3 -m style' '
+       git config merge.conflictstyle diff3 &&
+       git checkout -f initial^0 &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x &&
+       cat <<-EOF > expected &&
+       <<<<<<< HEAD
+       a
+       ||||||| objid picked
+       c
+       =======
+       b
+       >>>>>>> parent of objid picked
+       EOF
+
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD &&
+
+       test_must_fail git revert picked &&
+
+       sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
+       test_cmp expected actual
+'
+
+test_done
index 476e5ec038f3c9fd2cad4607c3819f54dabd04ad..8fe14ccc5444df95960bee88e5b79eb68156572b 100755 (executable)
@@ -228,4 +228,154 @@ test_expect_success 'stash --invalid-option' '
        test bar,bar2 = $(cat file),$(cat file2)
 '
 
+test_expect_success 'stash an added file' '
+       git reset --hard &&
+       echo new >file3 &&
+       git add file3 &&
+       git stash save "added file" &&
+       ! test -r file3 &&
+       git stash apply &&
+       test new = "$(cat file3)"
+'
+
+test_expect_success 'stash rm then recreate' '
+       git reset --hard &&
+       git rm file &&
+       echo bar7 >file &&
+       git stash save "rm then recreate" &&
+       test bar = "$(cat file)" &&
+       git stash apply &&
+       test bar7 = "$(cat file)"
+'
+
+test_expect_success 'stash rm and ignore' '
+       git reset --hard &&
+       git rm file &&
+       echo file >.gitignore &&
+       git stash save "rm and ignore" &&
+       test bar = "$(cat file)" &&
+       test file = "$(cat .gitignore)"
+       git stash apply &&
+       ! test -r file &&
+       test file = "$(cat .gitignore)"
+'
+
+test_expect_success 'stash rm and ignore (stage .gitignore)' '
+       git reset --hard &&
+       git rm file &&
+       echo file >.gitignore &&
+       git add .gitignore &&
+       git stash save "rm and ignore (stage .gitignore)" &&
+       test bar = "$(cat file)" &&
+       ! test -r .gitignore
+       git stash apply &&
+       ! test -r file &&
+       test file = "$(cat .gitignore)"
+'
+
+test_expect_success SYMLINKS 'stash file to symlink' '
+       git reset --hard &&
+       rm file &&
+       ln -s file2 file &&
+       git stash save "file to symlink" &&
+       test -f file &&
+       test bar = "$(cat file)" &&
+       git stash apply &&
+       case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+'
+
+test_expect_success SYMLINKS 'stash file to symlink (stage rm)' '
+       git reset --hard &&
+       git rm file &&
+       ln -s file2 file &&
+       git stash save "file to symlink (stage rm)" &&
+       test -f file &&
+       test bar = "$(cat file)" &&
+       git stash apply &&
+       case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+'
+
+test_expect_success SYMLINKS 'stash file to symlink (full stage)' '
+       git reset --hard &&
+       rm file &&
+       ln -s file2 file &&
+       git add file &&
+       git stash save "file to symlink (full stage)" &&
+       test -f file &&
+       test bar = "$(cat file)" &&
+       git stash apply &&
+       case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+'
+
+# This test creates a commit with a symlink used for the following tests
+
+test_expect_success SYMLINKS 'stash symlink to file' '
+       git reset --hard &&
+       ln -s file filelink &&
+       git add filelink &&
+       git commit -m "Add symlink" &&
+       rm filelink &&
+       cp file filelink &&
+       git stash save "symlink to file" &&
+       test -h filelink &&
+       case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+       git stash apply &&
+       ! test -h filelink &&
+       test bar = "$(cat file)"
+'
+
+test_expect_success SYMLINKS 'stash symlink to file (stage rm)' '
+       git reset --hard &&
+       git rm filelink &&
+       cp file filelink &&
+       git stash save "symlink to file (stage rm)" &&
+       test -h filelink &&
+       case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+       git stash apply &&
+       ! test -h filelink &&
+       test bar = "$(cat file)"
+'
+
+test_expect_success SYMLINKS 'stash symlink to file (full stage)' '
+       git reset --hard &&
+       rm filelink &&
+       cp file filelink &&
+       git add filelink &&
+       git stash save "symlink to file (full stage)" &&
+       test -h filelink &&
+       case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+       git stash apply &&
+       ! test -h filelink &&
+       test bar = "$(cat file)"
+'
+
+test_expect_failure 'stash directory to file' '
+       git reset --hard &&
+       mkdir dir &&
+       echo foo >dir/file &&
+       git add dir/file &&
+       git commit -m "Add file in dir" &&
+       rm -fr dir &&
+       echo bar >dir &&
+       git stash save "directory to file" &&
+       test -d dir &&
+       test foo = "$(cat dir/file)" &&
+       test_must_fail git stash apply &&
+       test bar = "$(cat dir)" &&
+       git reset --soft HEAD^
+'
+
+test_expect_failure 'stash file to directory' '
+       git reset --hard &&
+       rm file &&
+       mkdir file &&
+       echo foo >file/file &&
+       git stash save "file to directory" &&
+       test -f file &&
+       test bar = "$(cat file)" &&
+       git stash apply &&
+       test -f file/file &&
+       test foo = "$(cat file/file)"
+'
+
 test_done
index c7b625642dd57f4bcb6f7c5aa240cc9c32e15af8..d21c37f3a20c42b05044e45c5e5af71294c8420c 100755 (executable)
@@ -609,4 +609,8 @@ test_expect_success 'format-patch -- <path>' '
        ! grep "Use .--" error
 '
 
+test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
+       git format-patch --ignore-if-in-upstream HEAD
+'
+
 test_done
index 0391a5827ea8ba196b7796b7df818f8ac860c387..61589853df55e063fbe6489fc9c6effc4a9f33b6 100755 (executable)
@@ -120,7 +120,6 @@ test_expect_success '--check with --no-pager returns 2 for dirty difference' '
 
 '
 
-
 test_expect_success 'check should test not just the last line' '
        echo "" >>a &&
        git --no-pager diff --check
@@ -142,4 +141,26 @@ test_expect_success 'check detects leftover conflict markers' '
        git reset --hard
 '
 
+test_expect_success 'check honors conflict marker length' '
+       git reset --hard &&
+       echo ">>>>>>> boo" >>b &&
+       echo "======" >>a &&
+       git diff --check a &&
+       (
+               git diff --check b
+               test $? = 2
+       ) &&
+       git reset --hard &&
+       echo ">>>>>>>> boo" >>b &&
+       echo "========" >>a &&
+       git diff --check &&
+       echo "b conflict-marker-size=8" >.gitattributes &&
+       (
+               git diff --check b
+               test $? = 2
+       ) &&
+       git diff --check a &&
+       git reset --hard
+'
+
 test_done
index 7584efa36b06effd9005b8ebcc6afecec07e424b..40277c77aad5f2d9533e6822da3380bb49621e59 100755 (executable)
@@ -81,4 +81,12 @@ test_expect_success 'check combined output (2)' '
        verify_helper sidesansone
 '
 
+test_expect_success 'diagnose truncated file' '
+       >file &&
+       git add file &&
+       git commit --amend -C HEAD &&
+       git show >out &&
+       grep "diff --cc file" out
+'
+
 test_done
index 11b19972ca89f20faaa35b8a2c9fcd7f97181f78..019acb926d6765bf24e1dfe4bea2a9dba28ca797 100755 (executable)
@@ -329,4 +329,19 @@ index 0000000..$head7
 EOF
 "
 
+test_expect_success 'setup .git file for sm2' '
+       (cd sm2 &&
+        REAL="$(pwd)/../.real" &&
+        mv .git "$REAL"
+        echo "gitdir: $REAL" >.git)
+'
+
+test_expect_success 'diff --submodule with .git file' '
+       git diff --submodule HEAD^ >actual &&
+       diff actual - <<-EOF
+Submodule sm1 $head6...0000000 (submodule deleted)
+Submodule sm2 0000000...$head7 (new submodule)
+EOF
+'
+
 test_done
index fb9ad247bf76c07a8b6dbbb0d6bf1ab830041770..451d75e3fb2ea3efb17825f6af92fa3213c620aa 100755 (executable)
@@ -325,6 +325,18 @@ test_expect_success 'two missing blank lines at end with --whitespace=fix' '
        test_cmp one expect
 '
 
+test_expect_success 'missing blank line at end, insert before end, --whitespace=fix' '
+       { echo a; echo; } >one &&
+       git add one &&
+       { echo b; echo a; echo; } >one &&
+       cp one expect &&
+       git diff -- one >patch &&
+       echo a >one &&
+       test_must_fail git apply patch &&
+       git apply --whitespace=fix patch &&
+       test_cmp one expect
+'
+
 test_expect_success 'shrink file with tons of missing blanks at end of file' '
        { echo a; echo b; echo c; } >one &&
        cp one no-blank-lines &&
index a01e55bf6b96246c33332e5112bcb3d6583402ac..cdb70b4b3356eeb45bb6e5ac62d1f82eb6b3ccdc 100755 (executable)
@@ -8,30 +8,93 @@ test_description='git shortlog
 
 . ./test-lib.sh
 
-echo 1 > a1
-git add a1
-tree=$(git write-tree)
-commit=$( (echo "Test"; echo) | git commit-tree $tree )
-git update-ref HEAD $commit
+test_expect_success 'setup' '
+       echo 1 >a1 &&
+       git add a1 &&
+       tree=$(git write-tree) &&
+       commit=$(printf "%s\n" "Test" "" | git commit-tree "$tree") &&
+       git update-ref HEAD "$commit" &&
+
+       echo 2 >a1 &&
+       git commit --quiet -m "This is a very, very long first line for the commit message to see if it is wrapped correctly" a1 &&
+
+       # test if the wrapping is still valid
+       # when replacing all is by treble clefs.
+       echo 3 >a1 &&
+       git commit --quiet -m "$(
+               echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" |
+               sed "s/i/1234/g" |
+               tr 1234 "\360\235\204\236")" a1 &&
+
+       # now fsck up the utf8
+       git config i18n.commitencoding non-utf-8 &&
+       echo 4 >a1 &&
+       git commit --quiet -m "$(
+               echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" |
+               sed "s/i/1234/g" |
+               tr 1234 "\370\235\204\236")" a1 &&
+
+       echo 5 >a1 &&
+       git commit --quiet -m "a                                                                12      34      56      78" a1
+
+       echo 6 >a1 &&
+       git commit --quiet -m "Commit by someone else" \
+               --author="Someone else <not!me>" a1 &&
+
+       cat >expect.template <<-\EOF
+       A U Thor (5):
+             SUBJECT
+             SUBJECT
+             SUBJECT
+             SUBJECT
+             SUBJECT
+
+       Someone else (1):
+             SUBJECT
+
+       EOF
+'
 
-echo 2 > a1
-git commit --quiet -m "This is a very, very long first line for the commit message to see if it is wrapped correctly" a1
+fuzz() {
+       file=$1 &&
+       sed "
+                       s/$_x40/OBJECT_NAME/g
+                       s/$_x05/OBJID/g
+                       s/^ \{6\}[CTa].*/      SUBJECT/g
+                       s/^ \{8\}[^ ].*/        CONTINUATION/g
+               " <"$file" >"$file.fuzzy" &&
+       sed "/CONTINUATION/ d" <"$file.fuzzy"
+}
 
-# test if the wrapping is still valid when replacing all i's by treble clefs.
-echo 3 > a1
-git commit --quiet -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\360\235\204\236')" a1
+test_expect_success 'default output format' '
+       git shortlog HEAD >log &&
+       fuzz log >log.predictable &&
+       test_cmp expect.template log.predictable
+'
 
-# now fsck up the utf8
-git config i18n.commitencoding non-utf-8
-echo 4 > a1
-git commit --quiet -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\370\235\204\236')" a1
+test_expect_success 'pretty format' '
+       sed s/SUBJECT/OBJECT_NAME/ expect.template >expect &&
+       git shortlog --format="%H" HEAD >log &&
+       fuzz log >log.predictable &&
+       test_cmp expect log.predictable
+'
 
-echo 5 > a1
-git commit --quiet -m "a                                                               12      34      56      78" a1
+test_expect_success '--abbrev' '
+       sed s/SUBJECT/OBJID/ expect.template >expect &&
+       git shortlog --format="%h" --abbrev=5 HEAD >log &&
+       fuzz log >log.predictable &&
+       test_cmp expect log.predictable
+'
 
-git shortlog -w HEAD > out
+test_expect_success 'output from user-defined format is re-wrapped' '
+       sed "s/SUBJECT/two lines/" expect.template >expect &&
+       git shortlog --format="two%nlines" HEAD >log &&
+       fuzz log >log.predictable &&
+       test_cmp expect log.predictable
+'
 
-cat > expect << EOF
+test_expect_success 'shortlog wrapping' '
+       cat >expect <<\EOF &&
 A U Thor (5):
       Test
       This is a very, very long first line for the commit message to see if
@@ -43,14 +106,19 @@ A U Thor (5):
       a                                                                12      34
          56    78
 
-EOF
-
-test_expect_success 'shortlog wrapping' 'test_cmp expect out'
+Someone else (1):
+      Commit by someone else
 
-git log HEAD > log
-GIT_DIR=non-existing git shortlog -w < log > out
+EOF
+       git shortlog -w HEAD >out &&
+       test_cmp expect out
+'
 
-test_expect_success 'shortlog from non-git directory' 'test_cmp expect out'
+test_expect_success 'shortlog from non-git directory' '
+       git log HEAD >log &&
+       GIT_DIR=non-existing git shortlog -w <log >out &&
+       test_cmp expect out
+'
 
 iconvfromutf8toiso88591() {
        printf "%s" "$*" | iconv -f UTF-8 -t ISO8859-1
index f0f91f149d760f6b6458d10639725259973d7115..552da65a61e8f78d40f8e19cfc5b73696ebcf283 100755 (executable)
@@ -180,4 +180,20 @@ EOF
        verify_hook_input
 '
 
+test_expect_success 'git rebase -i (double edit)' '
+       git reset --hard D &&
+       clear_hook_input &&
+       FAKE_LINES="edit 1 edit 2" git rebase -i B &&
+       git rebase --continue &&
+       echo something > foo &&
+       git add foo &&
+       git rebase --continue &&
+       echo rebase >expected.args &&
+       cat >expected.data <<EOF &&
+$(git rev-parse C) $(git rev-parse HEAD^)
+$(git rev-parse D) $(git rev-parse HEAD)
+EOF
+       verify_hook_input
+'
+
 test_done
index 26920502093a98d4b5721f783e006de9d999792a..230c0cd784b317856749609cf64a5067e35a6965 100755 (executable)
@@ -110,17 +110,18 @@ test_expect_success 'remove remote' '
 test_expect_success 'remove remote protects non-remote branches' '
 (
        cd test &&
-       (cat >expect1 <<EOF
+       cat >expect1 <<EOF
 Note: A non-remote branch was not removed; to delete it, use:
   git branch -d master
 EOF
-    cat >expect2 <<EOF
+       } &&
+       { cat >expect2 <<EOF
 Note: Non-remote branches were not removed; to delete them, use:
   git branch -d foobranch
   git branch -d master
 EOF
-) &&
-       git tag footag
+       } &&
+       git tag footag &&
        git config --add remote.oops.fetch "+refs/*:refs/*" &&
        git remote rm oops 2>actual1 &&
        git branch foobranch &&
@@ -534,43 +535,34 @@ test_expect_success 'show empty remote' '
 '
 
 test_expect_success 'new remote' '
-(
        git remote add someremote foo &&
        echo foo >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url bar' '
-(
        git remote set-url someremote bar &&
        echo bar >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url baz bar' '
-(
        git remote set-url someremote baz bar &&
        echo baz >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url zot bar' '
-(
        test_must_fail git remote set-url someremote zot bar &&
        echo baz >expect &&
        git config --get-all remote.someremote.url >actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push zot baz' '
-(
        test_must_fail git remote set-url --push someremote zot baz &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -578,11 +570,9 @@ test_expect_success 'remote set-url --push zot baz' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push zot' '
-(
        git remote set-url --push someremote zot &&
        echo zot >expect &&
        echo "YYY" >>expect &&
@@ -591,11 +581,9 @@ test_expect_success 'remote set-url --push zot' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push qux zot' '
-(
        git remote set-url --push someremote qux zot &&
        echo qux >expect &&
        echo "YYY" >>expect &&
@@ -604,11 +592,9 @@ test_expect_success 'remote set-url --push qux zot' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push foo qu+x' '
-(
        git remote set-url --push someremote foo qu+x &&
        echo foo >expect &&
        echo "YYY" >>expect &&
@@ -617,11 +603,9 @@ test_expect_success 'remote set-url --push foo qu+x' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push --add aaa' '
-(
        git remote set-url --push --add someremote aaa &&
        echo foo >expect &&
        echo aaa >>expect &&
@@ -631,11 +615,9 @@ test_expect_success 'remote set-url --push --add aaa' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push bar aaa' '
-(
        git remote set-url --push someremote bar aaa &&
        echo foo >expect &&
        echo bar >>expect &&
@@ -645,11 +627,9 @@ test_expect_success 'remote set-url --push bar aaa' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push --delete bar' '
-(
        git remote set-url --push --delete someremote bar &&
        echo foo >expect &&
        echo "YYY" >>expect &&
@@ -658,11 +638,9 @@ test_expect_success 'remote set-url --push --delete bar' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --push --delete foo' '
-(
        git remote set-url --push --delete someremote foo &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -670,11 +648,9 @@ test_expect_success 'remote set-url --push --delete foo' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --add bbb' '
-(
        git remote set-url --add someremote bbb &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -683,12 +659,10 @@ test_expect_success 'remote set-url --add bbb' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete .*' '
-(
-       test_must_fail git remote set-url --delete someremote .* &&
+       test_must_fail git remote set-url --delete someremote .\* &&
        echo "YYY" >expect &&
        echo baz >>expect &&
        echo bbb >>expect &&
@@ -696,11 +670,9 @@ test_expect_success 'remote set-url --delete .*' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete bbb' '
-(
        git remote set-url --delete someremote bbb &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -708,11 +680,9 @@ test_expect_success 'remote set-url --delete bbb' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete baz' '
-(
        test_must_fail git remote set-url --delete someremote baz &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -720,11 +690,9 @@ test_expect_success 'remote set-url --delete baz' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --add ccc' '
-(
        git remote set-url --add someremote ccc &&
        echo "YYY" >expect &&
        echo baz >>expect &&
@@ -733,11 +701,9 @@ test_expect_success 'remote set-url --add ccc' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_expect_success 'remote set-url --delete baz' '
-(
        git remote set-url --delete someremote baz &&
        echo "YYY" >expect &&
        echo ccc >>expect &&
@@ -745,7 +711,6 @@ test_expect_success 'remote set-url --delete baz' '
        echo "YYY" >>actual &&
        git config --get-all remote.someremote.url >>actual &&
        cmp expect actual
-)
 '
 
 test_done
index 2de98e6561607b87bceef66c20ad9055d04878c3..6a37a4d993df3fa4958a719fdfdb82f0dd2de623 100755 (executable)
@@ -528,7 +528,7 @@ test_expect_success 'push does not update local refs on failure' '
        mk_test heads/master &&
        mk_child child &&
        mkdir testrepo/.git/hooks &&
-       echo exit 1 >testrepo/.git/hooks/pre-receive &&
+       echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive &&
        chmod +x testrepo/.git/hooks/pre-receive &&
        (cd child &&
                git pull .. master
index 795dc2bcdf98e582dd2f05d901b791ab4225ce3b..17e1bdc5a81ce4802f5074ddb9c1996c68fc97be 100755 (executable)
@@ -34,8 +34,34 @@ test_expect_success 'setup remote repository' '
        mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
 '
 
-test_expect_success 'clone remote repository' '
+cat >exp <<EOF
+GET  /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
+POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
+EOF
+test_expect_success 'no empty path components' '
+       # In the URL, add a trailing slash, and see if git appends yet another
+       # slash.
        cd "$ROOT_PATH" &&
+       git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone &&
+
+       sed -e "
+               s/^.* \"//
+               s/\"//
+               s/ [1-9][0-9]*\$//
+               s/^GET /GET  /
+       " >act <"$HTTPD_ROOT_PATH"/access.log &&
+
+       # Clear the log, so that it does not affect the "used receive-pack
+       # service" test which reads the log too.
+       #
+       # We do this before the actual comparison to ensure the log is cleared.
+       echo > "$HTTPD_ROOT_PATH"/access.log &&
+
+       test_cmp exp act
+'
+
+test_expect_success 'clone remote repository' '
+       rm -rf test_repo_clone &&
        git clone $HTTPD_URL/smart/test_repo.git test_repo_clone
 '
 
@@ -68,6 +94,7 @@ test_expect_success 'create and delete remote branch' '
 '
 
 cat >exp <<EOF
+
 GET  /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
 POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
 GET  /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
index 8cfce969bcdac6e2091e635dad9c58ca616e5c3b..fc675b50adfa945724cd7d17dbb6034df53426d3 100755 (executable)
@@ -55,12 +55,43 @@ test_expect_success 'http remote detects correct HEAD' '
 
 test_expect_success 'fetch packed objects' '
        cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
-       cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
-       git --bare repack &&
-       git --bare prune-packed &&
+       (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
+        git --bare repack &&
+        git --bare prune-packed
+       ) &&
        git clone $HTTPD_URL/dumb/repo_pack.git
 '
 
+test_expect_success 'fetch notices corrupt pack' '
+       cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+       (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+        p=`ls objects/pack/pack-*.pack` &&
+        chmod u+w $p &&
+        printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+       ) &&
+       mkdir repo_bad1.git &&
+       (cd repo_bad1.git &&
+        git --bare init &&
+        test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad1.git &&
+        test 0 = `ls objects/pack/pack-*.pack | wc -l`
+       )
+'
+
+test_expect_success 'fetch notices corrupt idx' '
+       cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+       (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+        p=`ls objects/pack/pack-*.idx` &&
+        chmod u+w $p &&
+        printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+       ) &&
+       mkdir repo_bad2.git &&
+       (cd repo_bad2.git &&
+        git --bare init &&
+        test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad2.git &&
+        test 0 = `ls objects/pack | wc -l`
+       )
+'
+
 test_expect_success 'did not use upload-pack service' '
        grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act
        : >exp
index 214756731baf199e6a50f9ab2380a8b4bfc0fb18..678cee502de54e5a9c18a43f114446d3392ec7f3 100755 (executable)
@@ -34,7 +34,7 @@ test_expect_success 'clone with excess parameters (2)' '
 test_expect_success 'output from clone' '
        rm -fr dst &&
        git clone -n "file://$(pwd)/src" dst >output &&
-       test $(grep Initialized output | wc -l) = 1
+       test $(grep Clon output | wc -l) = 1
 '
 
 test_expect_success 'clone does not keep pack' '
index a8f4419e610c4329cefc556684a7212f1405e104..ddc3dc52f497d05e20cf4034d544df6d08632935 100755 (executable)
@@ -30,4 +30,20 @@ test_expect_success 'tags can be excluded by rev-list options' '
 
 '
 
+test_expect_failure 'bundle --stdin' '
+
+       echo master | git bundle create stdin-bundle.bdl --stdin &&
+       git ls-remote stdin-bundle.bdl >output &&
+       grep master output
+
+'
+
+test_expect_failure 'bundle --stdin <rev-list options>' '
+
+       echo master | git bundle create hybrid-bundle.bdl --stdin tag &&
+       git ls-remote hybrid-bundle.bdl >output &&
+       grep master output
+
+'
+
 test_done
index adfaae8c5b453835eeeac3e3794950971e6dd6d8..8afbdd4de2146be763f7454af66a15986490fe60 100755 (executable)
@@ -12,7 +12,7 @@ test_expect_success 'setup' '
 
        git config pack.compression 0 &&
        git config pack.depth 0 &&
-       blobsize=$((20*1024*1024)) &&
+       blobsize=$((100*1024*1024)) &&
        blobcount=$((2*1024*1024*1024/$blobsize+1)) &&
        i=1 &&
        (while test $i -le $blobcount
@@ -36,9 +36,15 @@ test_expect_success 'setup' '
 
 '
 
-test_expect_success 'clone' '
+test_expect_success 'clone - bare' '
 
-       git clone --bare --no-hardlinks . clone
+       git clone --bare --no-hardlinks . clone-bare
+
+'
+
+test_expect_success 'clone - with worktree, file:// protocol' '
+
+       git clone file://. clone-wt
 
 '
 
diff --git a/t/t6000lib.sh b/t/t6000lib.sh
deleted file mode 100644 (file)
index 985d517..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-: included from 6002 and others
-
-[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
-
-:> sed.script
-
-# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
-tag()
-{
-       _tag=$1
-       [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
-       cat .git/refs/tags/$_tag
-}
-
-# Generate a commit using the text specified to make it unique and the tree
-# named by the tag specified.
-unique_commit()
-{
-       _text=$1
-        _tree=$2
-       shift 2
-       echo $_text | git commit-tree $(tag $_tree) "$@"
-}
-
-# Save the output of a command into the tag specified. Prepend
-# a substitution script for the tag onto the front of sed.script
-save_tag()
-{
-       _tag=$1
-       [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
-       shift 1
-       "$@" >.git/refs/tags/$_tag
-
-        echo "s/$(tag $_tag)/$_tag/g" > sed.script.tmp
-       cat sed.script >> sed.script.tmp
-       rm sed.script
-       mv sed.script.tmp sed.script
-}
-
-# Replace unhelpful sha1 hashses with their symbolic equivalents
-entag()
-{
-       sed -f sed.script
-}
-
-# Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
-# tag to a specified value. Restore the original value on return.
-as_author()
-{
-       _author=$1
-       shift 1
-        _save=$GIT_AUTHOR_EMAIL
-
-       GIT_AUTHOR_EMAIL="$_author"
-       export GIT_AUTHOR_EMAIL
-       "$@"
-       if test -z "$_save"
-       then
-               unset GIT_AUTHOR_EMAIL
-       else
-               GIT_AUTHOR_EMAIL="$_save"
-               export GIT_AUTHOR_EMAIL
-       fi
-}
-
-commit_date()
-{
-        _commit=$1
-       git cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
-}
-
-on_committer_date()
-{
-    _date=$1
-    shift 1
-    GIT_COMMITTER_DATE="$_date"
-    export GIT_COMMITTER_DATE
-    "$@"
-    unset GIT_COMMITTER_DATE
-}
-
-# Execute a command and suppress any error output.
-hide_error()
-{
-       "$@" 2>/dev/null
-}
-
-check_output()
-{
-       _name=$1
-       shift 1
-       if eval "$*" | entag > $_name.actual
-       then
-               diff $_name.expected $_name.actual
-       else
-               return 1;
-       fi
-}
-
-# Turn a reasonable test description into a reasonable test name.
-# All alphanums translated into -'s which are then compressed and stripped
-# from front and back.
-name_from_description()
-{
-       perl -pe '
-               s/[^A-Za-z0-9.]/-/g;
-               s/-+/-/g;
-               s/-$//;
-               s/^-//;
-               y/A-Z/a-z/;
-       '
-}
-
-
-# Execute the test described by the first argument, by eval'ing
-# command line specified in the 2nd argument. Check the status code
-# is zero and that the output matches the stream read from
-# stdin.
-test_output_expect_success()
-{
-       _description=$1
-        _test=$2
-        [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
-        _name=$(echo $_description | name_from_description)
-       cat > $_name.expected
-       test_expect_success "$_description" "check_output $_name \"$_test\""
-}
index b4e8fbaa5e6f2a56094c05ca505630669a51e101..fb07536a0f5b7e1000cf4945f55be3305df88e90 100755 (executable)
@@ -5,7 +5,7 @@
 test_description='Tests git rev-list --bisect functionality'
 
 . ./test-lib.sh
-. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions
+. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
 # usage: test_bisection max-diff bisect-option head ^prune...
 #
index 2c73f2da7b0a1f560bfd41376b587d1c91b18615..e4c52b0214b5028e8c3db035dc96ca3285e61506 100755 (executable)
@@ -6,7 +6,7 @@
 test_description='Tests git rev-list --topo-order functionality'
 
 . ./test-lib.sh
-. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions
+. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
 list_duplicates()
 {
index b0047d3c6b593795561ce908ab8e10ff574d3dbc..e8fde5c19c16f3fa2305ed319edb3289f4f758b9 100755 (executable)
@@ -191,6 +191,31 @@ test_expect_success 'add LF before non-empty (2)' '
        grep "^$" actual
 '
 
+test_expect_success '--abbrev' '
+       echo SHORT SHORT SHORT >expect2 &&
+       echo LONG LONG LONG >expect3 &&
+       git log -1 --format="%h %h %h" HEAD >actual1 &&
+       git log -1 --abbrev=5 --format="%h %h %h" HEAD >actual2 &&
+       git log -1 --abbrev=5 --format="%H %H %H" HEAD >actual3 &&
+       sed -e "s/$_x40/LONG/g" -e "s/$_x05/SHORT/g" <actual2 >fuzzy2 &&
+       sed -e "s/$_x40/LONG/g" -e "s/$_x05/SHORT/g" <actual3 >fuzzy3 &&
+       test_cmp expect2 fuzzy2 &&
+       test_cmp expect3 fuzzy3 &&
+       ! test_cmp actual1 actual2
+'
+
+test_expect_success '%H is not affected by --abbrev-commit' '
+       git log -1 --format=%H --abbrev-commit --abbrev=20 HEAD >actual &&
+       len=$(wc -c <actual) &&
+       test $len = 41
+'
+
+test_expect_success '%h is not affected by --abbrev-commit' '
+       git log -1 --format=%h --abbrev-commit --abbrev=20 HEAD >actual &&
+       len=$(wc -c <actual) &&
+       test $len = 21
+'
+
 test_expect_success '"%h %gD: %gs" is same as git-reflog' '
        git reflog >expect &&
        git log -g --format="%h %gD: %gs" >actual &&
@@ -203,10 +228,25 @@ test_expect_success '"%h %gD: %gs" is same as git-reflog (with date)' '
        test_cmp expect actual
 '
 
+test_expect_success '"%h %gD: %gs" is same as git-reflog (with --abbrev)' '
+       git reflog --abbrev=13 --date=raw >expect &&
+       git log -g --abbrev=13 --format="%h %gD: %gs" --date=raw >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success '%gd shortens ref name' '
        echo "master@{0}" >expect.gd-short &&
        git log -g -1 --format=%gd refs/heads/master >actual.gd-short &&
        test_cmp expect.gd-short actual.gd-short
 '
 
+test_expect_success 'oneline with empty message' '
+       git commit -m "dummy" --allow-empty &&
+       git commit -m "dummy" --allow-empty &&
+       git filter-branch --msg-filter "sed -e s/dummy//" HEAD^^.. &&
+       git rev-list --oneline HEAD >test.txt &&
+       test $(git rev-list --oneline HEAD | wc -l) -eq 5 &&
+       test $(git rev-list --oneline --graph HEAD | wc -l) -eq 5
+'
+
 test_done
index 5034dd1352c275beca4d5dae805cad6573a89aca..d486d73994cf563063b578ec5e212331e87bf67f 100755 (executable)
@@ -181,7 +181,7 @@ et nihil mihi deerit;
 
 In loco pascuae ibi me collocavit;
 super aquam refectionis educavit me.
-|||||||
+||||||| new5.txt
 et nihil mihi deerit.
 In loco pascuae ibi me collocavit,
 super aquam refectionis educavit me;
@@ -225,7 +225,7 @@ et nihil mihi deerit;
 
 In loco pascuae ibi me collocavit;
 super aquam refectionis educavit me.
-||||||||||
+|||||||||| new5.txt
 et nihil mihi deerit.
 In loco pascuae ibi me collocavit,
 super aquam refectionis educavit me;
index f105fab98e2d493ab489d345676101fc13096c22..e673c25e943f77430d7f61b0ab9e0b21e38e6915 100755 (executable)
@@ -6,7 +6,7 @@
 test_description='Test git rev-parse with different parent options'
 
 . ./test-lib.sh
-. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions
+. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
 
 date >path0
 git update-index --add path0
index 065deadc29eb3838f391ce758c4b188249dc87f9..876d1ab7430c2054ddc69bd3712ff769de52e774 100755 (executable)
@@ -8,7 +8,7 @@ test_description='test describe
  o----o----o----o----o----.    /
        \        A    c        /
         .------------o---o---o
-                     D   e
+                   D,R   e
 '
 . ./test-lib.sh
 
@@ -68,6 +68,8 @@ test_expect_success setup '
        echo D >another && git add another && git commit -m D &&
        test_tick &&
        git tag -a -m D D &&
+       test_tick &&
+       git tag -a -m R R &&
 
        test_tick &&
        echo DD >another && git commit -a -m another &&
@@ -89,10 +91,10 @@ test_expect_success setup '
 
 check_describe A-* HEAD
 check_describe A-* HEAD^
-check_describe D-* HEAD^^
+check_describe R-* HEAD^^
 check_describe A-* HEAD^^2
 check_describe B HEAD^^2^
-check_describe D-* HEAD^^^
+check_describe R-* HEAD^^^
 
 check_describe c-* --tags HEAD
 check_describe c-* --tags HEAD^
index 42f6fff373ba9707216279011b112c6c59af8780..42f8ece0978f38e10200a52ce8cf1952cf13ecbd 100755 (executable)
@@ -7,65 +7,69 @@ test_description='fmt-merge-msg test'
 
 . ./test-lib.sh
 
-datestamp=1151939923
-setdate () {
-       GIT_COMMITTER_DATE="$datestamp +0200"
-       GIT_AUTHOR_DATE="$datestamp +0200"
-       datestamp=`expr "$datestamp" + 1`
-       export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-}
-
 test_expect_success setup '
        echo one >one &&
        git add one &&
-       setdate &&
+       test_tick &&
        git commit -m "Initial" &&
 
+       git clone . remote &&
+
        echo uno >one &&
        echo dos >two &&
        git add two &&
-       setdate &&
+       test_tick &&
        git commit -a -m "Second" &&
 
        git checkout -b left &&
 
-       echo $datestamp >one &&
-       setdate &&
+       echo "c1" >one &&
+       test_tick &&
        git commit -a -m "Common #1" &&
 
-       echo $datestamp >one &&
-       setdate &&
+       echo "c2" >one &&
+       test_tick &&
        git commit -a -m "Common #2" &&
 
        git branch right &&
 
-       echo $datestamp >two &&
-       setdate &&
+       echo "l3" >two &&
+       test_tick &&
        git commit -a -m "Left #3" &&
 
-       echo $datestamp >two &&
-       setdate &&
+       echo "l4" >two &&
+       test_tick &&
        git commit -a -m "Left #4" &&
 
-       echo $datestamp >two &&
-       setdate &&
+       echo "l5" >two &&
+       test_tick &&
        git commit -a -m "Left #5" &&
+       git tag tag-l5 &&
 
        git checkout right &&
 
-       echo $datestamp >three &&
+       echo "r3" >three &&
        git add three &&
-       setdate &&
+       test_tick &&
        git commit -a -m "Right #3" &&
+       git tag tag-r3 &&
 
-       echo $datestamp >three &&
-       setdate &&
+       echo "r4" >three &&
+       test_tick &&
        git commit -a -m "Right #4" &&
 
-       echo $datestamp >three &&
-       setdate &&
+       echo "r5" >three &&
+       test_tick &&
        git commit -a -m "Right #5" &&
 
+       git checkout -b long &&
+       i=0 &&
+       while test $i -lt 30
+       do
+               test_commit $i one &&
+               i=$(($i+1))
+       done &&
+
        git show-branch
 '
 
@@ -113,7 +117,7 @@ test_expect_success 'merge-msg test #3-1' '
        git config merge.log true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -127,7 +131,7 @@ test_expect_success 'merge-msg test #3-2' '
        git config merge.summary true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -159,7 +163,7 @@ test_expect_success 'merge-msg test #4-1' '
        git config merge.log true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -173,7 +177,7 @@ test_expect_success 'merge-msg test #4-2' '
        git config merge.summary true &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -187,7 +191,7 @@ test_expect_success 'merge-msg test #5-1' '
        git config merge.log yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -201,7 +205,7 @@ test_expect_success 'merge-msg test #5-2' '
        git config merge.summary yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -215,7 +219,7 @@ test_expect_success 'merge-msg -F' '
        git config merge.summary yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
 
        git fmt-merge-msg -F .git/FETCH_HEAD >actual &&
@@ -229,7 +233,7 @@ test_expect_success 'merge-msg -F in subdirectory' '
        git config merge.summary yes &&
 
        git checkout master &&
-       setdate &&
+       test_tick &&
        git fetch . left right &&
        mkdir sub &&
        cp .git/FETCH_HEAD sub/FETCH_HEAD &&
@@ -240,4 +244,128 @@ test_expect_success 'merge-msg -F in subdirectory' '
        test_cmp expected actual
 '
 
+test_expect_success 'merge-msg with nothing to merge' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       (
+               cd remote &&
+               git checkout -b unrelated &&
+               test_tick &&
+               git fetch origin &&
+               git fmt-merge-msg <.git/FETCH_HEAD >../actual
+       ) &&
+
+       test_cmp /dev/null actual
+'
+
+cat >expected <<\EOF
+Merge tag 'tag-r3'
+
+* tag 'tag-r3':
+  Right #3
+  Common #2
+  Common #1
+EOF
+
+test_expect_success 'merge-msg tag' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       test_tick &&
+       git fetch . tag tag-r3 &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge tags 'tag-r3' and 'tag-l5'
+
+* tag 'tag-r3':
+  Right #3
+  Common #2
+  Common #1
+
+* tag 'tag-l5':
+  Left #5
+  Left #4
+  Left #3
+  Common #2
+  Common #1
+EOF
+
+test_expect_success 'merge-msg two tags' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       test_tick &&
+       git fetch . tag tag-r3 tag tag-l5 &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge branch 'left', tag 'tag-r3'
+
+* tag 'tag-r3':
+  Right #3
+  Common #2
+  Common #1
+
+* left:
+  Left #5
+  Left #4
+  Left #3
+  Common #2
+  Common #1
+EOF
+
+test_expect_success 'merge-msg tag and branch' '
+
+       git config --unset-all merge.log
+       git config --unset-all merge.summary
+       git config merge.summary yes &&
+
+       git checkout master &&
+       test_tick &&
+       git fetch . tag tag-r3 left &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+Merge branch 'long'
+
+* long: (35 commits)
+EOF
+
+test_expect_success 'merge-msg lots of commits' '
+
+       git checkout master &&
+       test_tick &&
+       git fetch . long &&
+
+       i=29 &&
+       while test $i -gt 9
+       do
+               echo "  $i" &&
+               i=$(($i-1))
+       done >>expected &&
+       echo "  ..." >>expected
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
 test_done
index 5257f4d261c2060b881d2649034232f76f4ed9b7..6355698c6b5d133988270b5c5ded3b0209b1bf03 100755 (executable)
@@ -13,7 +13,7 @@ test_expect_success 'determine default editor' '
 
 '
 
-if ! expr "$vi" : '^[a-z]*$' >/dev/null
+if ! expr "$vi" : '[a-z]*$' >/dev/null
 then
        vi=
 fi
index d9202d5af5a179ca0b77d6509e05cbe6bf092ccc..0f6b367832ed164a126abc6206e724a7a0e4feb0 100755 (executable)
@@ -4,17 +4,24 @@ test_description='Test automatic use of a pager.'
 
 . ./test-lib.sh
 
-rm -f stdout_is_tty
+cleanup_fail() {
+       echo >&2 cleanup failed
+       (exit 1)
+}
+
 test_expect_success 'set up terminal for tests' '
+       rm -f stdout_is_tty ||
+       cleanup_fail &&
+
        if test -t 1
        then
-               : > stdout_is_tty
+               >stdout_is_tty
        elif
                test_have_prereq PERL &&
                "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl \
                        sh -c "test -t 1"
        then
-               : > test_terminal_works
+               >test_terminal_works
        fi
 '
 
@@ -32,53 +39,68 @@ else
        say no usable terminal, so skipping some tests
 fi
 
-unset GIT_PAGER GIT_PAGER_IN_USE
-git config --unset core.pager
-PAGER='cat > paginated.out'
-export PAGER
-
 test_expect_success 'setup' '
+       unset GIT_PAGER GIT_PAGER_IN_USE &&
+       test_might_fail git config --unset core.pager &&
+
+       PAGER="cat >paginated.out" &&
+       export PAGER &&
+
        test_commit initial
 '
 
-rm -f paginated.out
 test_expect_success TTY 'some commands use a pager' '
+       rm -f paginated.out ||
+       cleanup_fail &&
+
        test_terminal git log &&
        test -e paginated.out
 '
 
-rm -f paginated.out
 test_expect_success TTY 'some commands do not use a pager' '
+       rm -f paginated.out ||
+       cleanup_fail &&
+
        test_terminal git rev-list HEAD &&
        ! test -e paginated.out
 '
 
-rm -f paginated.out
 test_expect_success 'no pager when stdout is a pipe' '
+       rm -f paginated.out ||
+       cleanup_fail &&
+
        git log | cat &&
        ! test -e paginated.out
 '
 
-rm -f paginated.out
 test_expect_success 'no pager when stdout is a regular file' '
-       git log > file &&
+       rm -f paginated.out ||
+       cleanup_fail &&
+
+       git log >file &&
        ! test -e paginated.out
 '
 
-rm -f paginated.out
 test_expect_success TTY 'git --paginate rev-list uses a pager' '
+       rm -f paginated.out ||
+       cleanup_fail &&
+
        test_terminal git --paginate rev-list HEAD &&
        test -e paginated.out
 '
 
-rm -f file paginated.out
 test_expect_success 'no pager even with --paginate when stdout is a pipe' '
+       rm -f file paginated.out ||
+       cleanup_fail &&
+
        git --paginate log | cat &&
        ! test -e paginated.out
 '
 
-rm -f paginated.out
 test_expect_success TTY 'no pager with --no-pager' '
+       rm -f paginated.out ||
+       cleanup_fail &&
+
        test_terminal git --no-pager log &&
        ! test -e paginated.out
 '
@@ -86,88 +108,119 @@ test_expect_success TTY 'no pager with --no-pager' '
 # A colored commit log will begin with an appropriate ANSI escape
 # for the first color; the text "commit" comes later.
 colorful() {
-       read firstline < $1
-       ! expr "$firstline" : "^[a-zA-Z]" >/dev/null
+       read firstline <$1
+       ! expr "$firstline" : "[a-zA-Z]" >/dev/null
 }
 
-rm -f colorful.log colorless.log
 test_expect_success 'tests can detect color' '
-       git log --no-color > colorless.log &&
-       git log --color > colorful.log &&
+       rm -f colorful.log colorless.log ||
+       cleanup_fail &&
+
+       git log --no-color >colorless.log &&
+       git log --color >colorful.log &&
        ! colorful colorless.log &&
        colorful colorful.log
 '
 
-rm -f colorless.log
-git config color.ui auto
 test_expect_success 'no color when stdout is a regular file' '
-       git log > colorless.log &&
+       rm -f colorless.log &&
+       git config color.ui auto ||
+       cleanup_fail &&
+
+       git log >colorless.log &&
        ! colorful colorless.log
 '
 
-rm -f paginated.out
-git config color.ui auto
 test_expect_success TTY 'color when writing to a pager' '
-       TERM=vt100 test_terminal git log &&
+       rm -f paginated.out &&
+       git config color.ui auto ||
+       cleanup_fail &&
+
+       (
+               TERM=vt100 &&
+               export TERM &&
+               test_terminal git log
+       ) &&
        colorful paginated.out
 '
 
-rm -f colorful.log
-git config color.ui auto
 test_expect_success 'color when writing to a file intended for a pager' '
-       TERM=vt100 GIT_PAGER_IN_USE=true git log > colorful.log &&
+       rm -f colorful.log &&
+       git config color.ui auto ||
+       cleanup_fail &&
+
+       (
+               TERM=vt100 &&
+               GIT_PAGER_IN_USE=true &&
+               export TERM GIT_PAGER_IN_USE &&
+               git log >colorful.log
+       ) &&
        colorful colorful.log
 '
 
-unset PAGER GIT_PAGER
-git config --unset core.pager
 test_expect_success 'determine default pager' '
+       unset PAGER GIT_PAGER &&
+       test_might_fail git config --unset core.pager ||
+       cleanup_fail &&
+
        less=$(git var GIT_PAGER) &&
        test -n "$less"
 '
 
-if expr "$less" : '^[a-z]*$' > /dev/null && test_have_prereq TTY
+if expr "$less" : '[a-z][a-z]*$' >/dev/null && test_have_prereq TTY
 then
        test_set_prereq SIMPLEPAGER
 fi
 
-unset PAGER GIT_PAGER
-git config --unset core.pager
-rm -f default_pager_used
 test_expect_success SIMPLEPAGER 'default pager is used by default' '
-       cat > $less <<-EOF &&
-       #!$SHELL_PATH
-       wc > default_pager_used
+       unset PAGER GIT_PAGER &&
+       test_might_fail git config --unset core.pager &&
+       rm -f default_pager_used ||
+       cleanup_fail &&
+
+       cat >$less <<-\EOF &&
+       #!/bin/sh
+       wc >default_pager_used
        EOF
        chmod +x $less &&
-       PATH=.:$PATH test_terminal git log &&
+       (
+               PATH=.:$PATH &&
+               export PATH &&
+               test_terminal git log
+       ) &&
        test -e default_pager_used
 '
 
-unset GIT_PAGER
-git config --unset core.pager
-rm -f PAGER_used
 test_expect_success TTY 'PAGER overrides default pager' '
-       PAGER="wc > PAGER_used" &&
+       unset GIT_PAGER &&
+       test_might_fail git config --unset core.pager &&
+       rm -f PAGER_used ||
+       cleanup_fail &&
+
+       PAGER="wc >PAGER_used" &&
        export PAGER &&
        test_terminal git log &&
        test -e PAGER_used
 '
 
-unset GIT_PAGER
-rm -f core.pager_used
 test_expect_success TTY 'core.pager overrides PAGER' '
+       unset GIT_PAGER &&
+       rm -f core.pager_used ||
+       cleanup_fail &&
+
        PAGER=wc &&
        export PAGER &&
-       git config core.pager "wc > core.pager_used" &&
+       git config core.pager "wc >core.pager_used" &&
        test_terminal git log &&
        test -e core.pager_used
 '
 
-rm -f GIT_PAGER_used
 test_expect_success TTY 'GIT_PAGER overrides core.pager' '
+       rm -f GIT_PAGER_used ||
+       cleanup_fail &&
+
        git config core.pager wc &&
-       GIT_PAGER="wc > GIT_PAGER_used" &&
+       GIT_PAGER="wc >GIT_PAGER_used" &&
        export GIT_PAGER &&
        test_terminal git log &&
        test -e GIT_PAGER_used
index 8d8b1c0e25e857945b17ed5ae4a9abc5f8987bd3..582d0b54f1f1a32459727e59932e95c4b466951f 100755 (executable)
@@ -136,11 +136,11 @@ test_expect_success 'git-clean, dirty case' '
        test_cmp expected result
 '
 
-test_expect_failure 'git-apply adds file' false
-test_expect_failure 'git-apply updates file' false
-test_expect_failure 'git-apply removes file' false
-test_expect_failure 'git-mv to skip-worktree' false
-test_expect_failure 'git-mv from skip-worktree' false
-test_expect_failure 'git-checkout' false
+#TODO test_expect_failure 'git-apply adds file' false
+#TODO test_expect_failure 'git-apply updates file' false
+#TODO test_expect_failure 'git-apply removes file' false
+#TODO test_expect_failure 'git-mv to skip-worktree' false
+#TODO test_expect_failure 'git-mv from skip-worktree' false
+#TODO test_expect_failure 'git-checkout' false
 
 test_done
index d20ed61b481539b25c054c49bd82aa6fb9b3a981..1337fa5a2209d489c43f0a34c95a89053d3fd8bf 100755 (executable)
@@ -11,10 +11,12 @@ Test switching across them.
   ! [master] Initial A one, A two
    * [renamer] Renamer R one->uno, M two
     ! [side] Side M one, D two, A three
-  ---
-    + [side] Side M one, D two, A three
-   *  [renamer] Renamer R one->uno, M two
-  +*+ [master] Initial A one, A two
+     ! [simple] Simple D one, M two
+  ----
+     + [simple] Simple D one, M two
+    +  [side] Side M one, D two, A three
+   *   [renamer] Renamer R one->uno, M two
+  +*++ [master] Initial A one, A two
 
 '
 
@@ -52,6 +54,11 @@ test_expect_success setup '
        git update-index --add --remove one two three &&
        git commit -m "Side M one, D two, A three" &&
 
+       git checkout -b simple master &&
+       rm -f one &&
+       fill a c e > two &&
+       git commit -a -m "Simple D one, M two" &&
+
        git checkout master
 '
 
@@ -166,6 +173,56 @@ test_expect_success 'checkout -m with merge conflict' '
        ! test -s current
 '
 
+test_expect_success 'format of merge conflict from checkout -m' '
+
+       git checkout -f master && git clean -f &&
+
+       fill b d > two &&
+       git checkout -m simple &&
+
+       git ls-files >current &&
+       fill same two two two >expect &&
+       test_cmp current expect &&
+
+       cat <<-EOF >expect &&
+       <<<<<<< simple
+       a
+       c
+       e
+       =======
+       b
+       d
+       >>>>>>> local
+       EOF
+       test_cmp two expect
+'
+
+test_expect_success 'checkout --merge --conflict=diff3 <branch>' '
+
+       git checkout -f master && git reset --hard && git clean -f &&
+
+       fill b d > two &&
+       git checkout --merge --conflict=diff3 simple &&
+
+       cat <<-EOF >expect &&
+       <<<<<<< simple
+       a
+       c
+       e
+       ||||||| master
+       a
+       b
+       c
+       d
+       e
+       =======
+       b
+       d
+       >>>>>>> local
+       EOF
+       test_cmp two expect
+'
+
 test_expect_success 'checkout to detach HEAD (with advice declined)' '
 
        git config advice.detachedHead false &&
@@ -481,7 +538,7 @@ test_expect_success 'checkout with --merge, in diff3 -m style' '
        (
                echo "<<<<<<< ours"
                echo ourside
-               echo "|||||||"
+               echo "||||||| base"
                echo original
                echo "======="
                echo theirside
@@ -525,7 +582,7 @@ test_expect_success 'checkout --conflict=diff3' '
        (
                echo "<<<<<<< ours"
                echo ourside
-               echo "|||||||"
+               echo "||||||| base"
                echo original
                echo "======="
                echo theirside
index 844fb43c6db1ae4e9b8a3cda6156af359e9f639e..95044668ee182fc2c1091fba7680e0576f7854bd 100755 (executable)
@@ -35,7 +35,7 @@ test_expect_success 'partial' '
 
 '
 
-test_expect_success 'partial modification in a subdirecotry' '
+test_expect_success 'partial modification in a subdirectory' '
 
        test_tick &&
        git commit -m "partial commit to subdirectory" not &&
index aeec1f6142e622ffc7b0ef8a68fe7734c02d24d0..3d4f85d74f6f378d76bde77e581273af010ba452 100755 (executable)
@@ -157,6 +157,22 @@ test_expect_success 'status with added and untracked file in modified submodule
        EOF
 '
 
+test_expect_success 'setup .git file for sub' '
+       (cd sub &&
+        rm -f new-file
+        REAL="$(pwd)/../.real" &&
+        mv .git "$REAL"
+        echo "gitdir: $REAL" >.git) &&
+        echo .real >>.gitignore &&
+        git commit -m "added .real to .gitignore" .gitignore
+'
+
+test_expect_success 'status with added file in modified submodule with .git file' '
+       (cd sub && git reset --hard && echo >foo && git add foo) &&
+       git status >output &&
+       grep "modified:   sub (new commits, modified content)" output
+'
+
 test_expect_success 'rm submodule contents' '
        rm -rf sub/* sub/.git
 '
index 556d0faa77e027c8a18e213088fa6bbc5d7e7af5..008d5711b818a315136290c141c830cdf5af80a0 100755 (executable)
@@ -68,6 +68,34 @@ test_expect_success 'status (2)' '
 
 '
 
+cat >expect <<\EOF
+# On branch master
+# Changes to be committed:
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#      modified:   dir1/modified
+#
+# Untracked files:
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+
+git config advice.statusHints false
+
+test_expect_success 'status (advice.statusHints false)' '
+
+       git status >output &&
+       test_cmp expect output
+
+'
+
+git config --unset advice.statusHints
+
 cat >expect <<\EOF
  M dir1/modified
 A  dir2/added
@@ -115,6 +143,23 @@ test_expect_success 'status (status.showUntrackedFiles no)' '
        test_cmp expect output
 '
 
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#      new file:   dir2/added
+#
+# Changed but not updated:
+#      modified:   dir1/modified
+#
+# Untracked files not listed
+EOF
+git config advice.statusHints false
+test_expect_success 'status -uno (advice.statusHints false)' '
+       git status -uno >output &&
+       test_cmp expect output
+'
+git config --unset advice.statusHints
+
 cat >expect << EOF
  M dir1/modified
 A  dir2/added
@@ -496,6 +541,16 @@ test_expect_success 'dry-run of partial commit excluding new file in index' '
        test_cmp expect output
 '
 
+cat >expect <<EOF
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 M     dir1/modified
+EOF
+test_expect_success 'status refreshes the index' '
+       touch dir2/added &&
+       git status &&
+       git diff-files >output &&
+       test_cmp expect output
+'
+
 test_expect_success 'setup status submodule summary' '
        test_create_repo sm && (
                cd sm &&
@@ -693,4 +748,19 @@ test_expect_success 'commit --dry-run submodule summary (--amend)' '
        test_cmp expect output
 '
 
+test_expect_success POSIXPERM 'status succeeds in a read-only repository' '
+       (
+               chmod a-w .git &&
+               # make dir1/tracked stat-dirty
+               >dir1/tracked1 && mv -f dir1/tracked1 dir1/tracked &&
+               git status -s >output &&
+               ! grep dir1/tracked output &&
+               # make sure "status" succeeded without writing index out
+               git diff-files | grep dir1/tracked
+       )
+       status=$?
+       chmod 775 .git
+       (exit $status)
+'
+
 test_done
index 19c72f55bf60c746f72e640e24043b2d83e00fe3..1de83ef98fdcbfd63469e66ba4886c2477b983ff 100755 (executable)
@@ -92,6 +92,15 @@ test_expect_success 'difftool honors --gui' '
        restore_test_defaults
 '
 
+test_expect_success 'difftool --gui works without configured diff.guitool' '
+       git config diff.tool test-tool &&
+
+       diff=$(git difftool --no-prompt --gui branch) &&
+       test "$diff" = "branch" &&
+
+       restore_test_defaults
+'
+
 # Specify the diff tool using $GIT_DIFF_TOOL
 test_expect_success 'GIT_DIFF_TOOL variable' '
        git config --unset diff.tool
index 356964e53a1acba1558881865fd99acdee48a17f..d43f37ccafb4ecf6f649a5504d2626f652d48d02 100755 (executable)
@@ -150,20 +150,22 @@ test_expect_success 'setup submodule' '
 
        git checkout -f master &&
        mkdir sub &&
-       cd sub &&
-       git init  &&
-       echo test file > file &&
-       git add file &&
-       git commit -m sub_initial &&
-       cd .. &&
+       (
+               cd sub &&
+               git init  &&
+               echo test file > file &&
+               git add file &&
+               git commit -m sub_initial
+       ) &&
        git submodule add "`pwd`/sub" sub &&
        git commit -m initial &&
        test_tick &&
-       cd sub &&
-       echo more data >> file &&
-       git add file &&
-       git commit -m sub_second &&
-       cd .. &&
+       (
+               cd sub &&
+               echo more data >> file &&
+               git add file &&
+               git commit -m sub_second
+       ) &&
        git add sub &&
        git commit -m second
 
@@ -264,19 +266,20 @@ test_expect_success 'cope with tagger-less tags' '
 
 test_expect_success 'setup for limiting exports by PATH' '
        mkdir limit-by-paths &&
-       cd limit-by-paths &&
-       git init &&
-       echo hi > there &&
-       git add there &&
-       git commit -m "First file" &&
-       echo foo > bar &&
-       git add bar &&
-       git commit -m "Second file" &&
-       git tag -a -m msg mytag &&
-       echo morefoo >> bar &&
-       git add bar &&
-       git commit -m "Change to second file" &&
-       cd ..
+       (
+               cd limit-by-paths &&
+               git init &&
+               echo hi > there &&
+               git add there &&
+               git commit -m "First file" &&
+               echo foo > bar &&
+               git add bar &&
+               git commit -m "Second file" &&
+               git tag -a -m msg mytag &&
+               echo morefoo >> bar &&
+               git add bar &&
+               git commit -m "Change to second file"
+       )
 '
 
 cat > limit-by-paths/expected << EOF
@@ -297,10 +300,11 @@ M 100644 :1 there
 EOF
 
 test_expect_success 'dropping tag of filtered out object' '
+(
        cd limit-by-paths &&
        git fast-export --tag-of-filtered-object=drop mytag -- there > output &&
-       test_cmp output expected &&
-       cd ..
+       test_cmp output expected
+)
 '
 
 cat >> limit-by-paths/expected << EOF
@@ -313,10 +317,11 @@ msg
 EOF
 
 test_expect_success 'rewriting tag of filtered out object' '
+(
        cd limit-by-paths &&
        git fast-export --tag-of-filtered-object=rewrite mytag -- there > output &&
-       test_cmp output expected &&
-       cd ..
+       test_cmp output expected
+)
 '
 
 cat > limit-by-paths/expected << EOF
@@ -343,13 +348,13 @@ M 100644 :2 there
 EOF
 
 test_expect_failure 'no exact-ref revisions included' '
-       cd limit-by-paths &&
-       git fast-export master~2..master~1 > output &&
-       test_cmp output expected &&
-       cd ..
+       (
+               cd limit-by-paths &&
+               git fast-export master~2..master~1 > output &&
+               test_cmp output expected
+       )
 '
 
-
 test_expect_success 'set-up a few more tags for tag export tests' '
        git checkout -f master &&
        HEAD_TREE=`git show -s --pretty=raw HEAD | grep tree | sed "s/tree //"` &&
index c582964b0d26bedcc69b4f7cc787c4deccfab6b9..9bfa14be7f1c3935013d04318eeaecc68b4ef88c 100644 (file)
@@ -2,6 +2,18 @@
 #
 # Copyright (c) 2005 Junio C Hamano
 #
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see http://www.gnu.org/licenses/ .
 
 # if --tee was passed, write the output not only to the terminal, but
 # additionally to the file test-results/$BASENAME.out, too.
@@ -354,8 +366,10 @@ test_debug () {
 }
 
 test_run_ () {
+       test_cleanup=:
        eval >&3 2>&4 "$1"
-       eval_ret="$?"
+       eval_ret=$?
+       eval >&3 2>&4 "$test_cleanup"
        return 0
 }
 
@@ -516,6 +530,22 @@ test_must_fail () {
        test $? -gt 0 -a $? -le 129 -o $? -gt 192
 }
 
+# Similar to test_must_fail, but tolerates success, too.  This is
+# meant to be used in contexts like:
+#
+#      test_expect_success 'some command works without configuration' '
+#              test_might_fail git config --unset all.configuration &&
+#              do something
+#      '
+#
+# Writing "git config --unset all.configuration || :" would be wrong,
+# because we want to notice if it fails due to segv.
+
+test_might_fail () {
+       "$@"
+       test $? -ge 0 -a $? -le 129 -o $? -gt 192
+}
+
 # test_cmp is a helper function to compare actual and expected output.
 # You can use it like:
 #
@@ -533,6 +563,31 @@ test_cmp() {
        $GIT_TEST_CMP "$@"
 }
 
+# This function can be used to schedule some commands to be run
+# unconditionally at the end of the test to restore sanity:
+#
+#      test_expect_success 'test core.capslock' '
+#              git config core.capslock true &&
+#              test_when_finished "git config --unset core.capslock" &&
+#              hello world
+#      '
+#
+# That would be roughly equivalent to
+#
+#      test_expect_success 'test core.capslock' '
+#              git config core.capslock true &&
+#              hello world
+#              git config --unset core.capslock
+#      '
+#
+# except that the greeting and config --unset must both succeed for
+# the test to pass.
+
+test_when_finished () {
+       test_cleanup="{ $*
+               } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
+}
+
 # Most tests can use the created repository, but some may need to create more.
 # Usage: test_create_repo <directory>
 test_create_repo () {
diff --git a/tag.c b/tag.c
index 4470d2bf78e1fbb00d00e487f41daa4373cf48e1..85607c219e25d63b0d1f3344649104c60f5b96e2 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -36,43 +36,50 @@ struct tag *lookup_tag(const unsigned char *sha1)
         return (struct tag *) obj;
 }
 
+static unsigned long parse_tag_date(const char *buf, const char *tail)
+{
+       const char *dateptr;
+
+       while (buf < tail && *buf++ != '>')
+               /* nada */;
+       if (buf >= tail)
+               return 0;
+       dateptr = buf;
+       while (buf < tail && *buf++ != '\n')
+               /* nada */;
+       if (buf >= tail)
+               return 0;
+       /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
+       return strtoul(dateptr, NULL, 10);
+}
+
 int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
 {
-       int typelen, taglen;
        unsigned char sha1[20];
-       const char *type_line, *tag_line, *sig_line;
        char type[20];
-       const char *start = data;
+       const char *bufptr = data;
+       const char *tail = bufptr + size;
+       const char *nl;
 
-        if (item->object.parsed)
-                return 0;
-        item->object.parsed = 1;
+       if (item->object.parsed)
+               return 0;
+       item->object.parsed = 1;
 
        if (size < 64)
                return -1;
-       if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, sha1))
+       if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
                return -1;
+       bufptr += 48; /* "object " + sha1 + "\n" */
 
-       type_line = (char *) data + 48;
-       if (memcmp("\ntype ", type_line-1, 6))
+       if (prefixcmp(bufptr, "type "))
                return -1;
-
-       tag_line = memchr(type_line, '\n', size - (type_line - start));
-       if (!tag_line || memcmp("tag ", ++tag_line, 4))
+       bufptr += 5;
+       nl = memchr(bufptr, '\n', tail - bufptr);
+       if (!nl || sizeof(type) <= (nl - bufptr))
                return -1;
-
-       sig_line = memchr(tag_line, '\n', size - (tag_line - start));
-       if (!sig_line)
-               return -1;
-       sig_line++;
-
-       typelen = tag_line - type_line - strlen("type \n");
-       if (typelen >= 20)
-               return -1;
-       memcpy(type, type_line + 5, typelen);
-       type[typelen] = '\0';
-       taglen = sig_line - tag_line - strlen("tag \n");
-       item->tag = xmemdupz(tag_line + 4, taglen);
+       strncpy(type, bufptr, nl - bufptr);
+       type[nl - bufptr] = '\0';
+       bufptr = nl + 1;
 
        if (!strcmp(type, blob_type)) {
                item->tagged = &lookup_blob(sha1)->object;
@@ -87,6 +94,20 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
                item->tagged = NULL;
        }
 
+       if (prefixcmp(bufptr, "tag "))
+               return -1;
+       bufptr += 4;
+       nl = memchr(bufptr, '\n', tail - bufptr);
+       if (!nl)
+               return -1;
+       item->tag = xmemdupz(bufptr, nl - bufptr);
+       bufptr = nl + 1;
+
+       if (!prefixcmp(bufptr, "tagger "))
+               item->date = parse_tag_date(bufptr, tail);
+       else
+               item->date = 0;
+
        return 0;
 }
 
diff --git a/tag.h b/tag.h
index 7a0cb0070d46ba8c49d71029dc0704188805ea62..47662724a6d7d07eeeacd5c8528d94d750ecf878 100644 (file)
--- a/tag.h
+++ b/tag.h
@@ -9,7 +9,7 @@ struct tag {
        struct object object;
        struct object *tagged;
        char *tag;
-       char *signature; /* not actually implemented */
+       unsigned long date;
 };
 
 extern struct tag *lookup_tag(const unsigned char *sha1);
index 408f0137a8342414eedba3a02372ea1ad6050117..d22a71a3999b3dc0e99f5e36053447b33f967bd7 100644 (file)
@@ -11,6 +11,16 @@ prefix ?= $(HOME)
 template_instdir ?= $(prefix)/share/git-core/templates
 # DESTDIR=
 
+ifndef SHELL_PATH
+       SHELL_PATH = /bin/sh
+endif
+ifndef PERL_PATH
+       PERL_PATH = perl
+endif
+
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+
 # Shell quote (do not use $(call) to accommodate ancient setups);
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 template_instdir_SQ = $(subst ','\'',$(template_instdir))
@@ -33,8 +43,11 @@ boilerplates.made : $(bpsrc)
                case "$$boilerplate" in \
                *--) continue;; \
                esac && \
-               cp $$boilerplate blt/$$dst && \
-               if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \
+               sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+                   -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
+                   -e 's|@PERL_PATH@|$(PERL_PATH_SQ)|g' $$boilerplate > \
+                       blt/$$dst && \
+               if test -x "$$boilerplate"; then rx=rx; else rx=r; fi && \
                chmod a+$$rx "blt/$$dst" || exit; \
        done && \
        date >$@
index 6ef1d29d09a10a5b6c3cbec0ac481931cd0d85fc..b58d1184a9d43a39c0d95f32453efc78581877d6 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # An example hook script to check the commit log message.
-# Called by git-commit with one argument, the name of the file
+# Called by "git commit" with one argument, the name of the file
 # that has the commit message.  The hook should exit with non-zero
 # status after issuing an appropriate message if it wants to stop the
 # commit.  The hook is allowed to edit the commit message file.
index 5323b56b81b9dd3d7f9fb86d8892241becbb5e7e..ec17ec1939b7c3e86b7cb6c0c4de6b0818a7e75e 100755 (executable)
@@ -5,4 +5,4 @@
 #
 # To enable this hook, rename this file to "post-update".
 
-exec git-update-server-info
+exec git update-server-info
index 439eefda510ca8de9f55c63616f2113ac36c8b6b..b187c4bb1f256e19c25f80dd64f3451ced77e123 100755 (executable)
@@ -1,13 +1,13 @@
 #!/bin/sh
 #
 # An example hook script to verify what is about to be committed.
-# Called by git-commit with no arguments.  The hook should
+# Called by "git commit" with no arguments.  The hook should
 # exit with non-zero status after issuing an appropriate message if
 # it wants to stop the commit.
 #
 # To enable this hook, rename this file to "pre-commit".
 
-if git-rev-parse --verify HEAD >/dev/null 2>&1
+if git rev-parse --verify HEAD >/dev/null 2>&1
 then
        against=HEAD
 else
index be1b06e25043146f22261b55548229e6ab524b7c..053f1111c0d734c057e895cdc992188104cc4f84 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Copyright (c) 2006, 2008 Junio C Hamano
 #
-# The "pre-rebase" hook is run just before "git-rebase" starts doing
+# The "pre-rebase" hook is run just before "git rebase" starts doing
 # its job, and can prevent the command from running by exiting with
 # non-zero status.
 #
@@ -43,7 +43,7 @@ git show-ref -q "$topic" || {
 }
 
 # Is topic fully merged to master?
-not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
+not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
 if test -z "$not_in_master"
 then
        echo >&2 "$topic is fully merged to master; better remove it."
@@ -51,11 +51,11 @@ then
 fi
 
 # Is topic ever merged to next?  If so you should not be rebasing it.
-only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
-only_next_2=`git-rev-list ^master           ${publish} | sort`
+only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git rev-list ^master           ${publish} | sort`
 if test "$only_next_1" = "$only_next_2"
 then
-       not_in_topic=`git-rev-list "^$topic" master`
+       not_in_topic=`git rev-list "^$topic" master`
        if test -z "$not_in_topic"
        then
                echo >&2 "$topic is already up-to-date with master"
@@ -64,8 +64,8 @@ then
                exit 0
        fi
 else
-       not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
-       perl -e '
+       not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
+       @PERL_PATH@ -e '
                my $topic = $ARGV[0];
                my $msg = "* $topic has commits already merged to public branch:\n";
                my (%not_in_next) = map {
@@ -157,13 +157,13 @@ B to be deleted.
 
 To compute (1):
 
-       git-rev-list ^master ^topic next
-       git-rev-list ^master        next
+       git rev-list ^master ^topic next
+       git rev-list ^master        next
 
        if these match, topic has not merged in next at all.
 
 To compute (2):
 
-       git-rev-list master..topic
+       git rev-list master..topic
 
        if this is empty, it is fully merged to "master".
index 365242499dcf0ee35c26ccb2917724d6e559be69..86b8f227ecab874a4af98bc5ba3164d370e5e4b5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # An example hook script to prepare the commit log message.
-# Called by git-commit with the name of the file that has the
+# Called by "git commit" with the name of the file that has the
 # commit message, followed by the description of the commit
 # message's source.  The hook's purpose is to edit the commit
 # message file.  If the hook fails with a non-zero status,
 
 case "$2,$3" in
   merge,)
-    perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+    @PERL_PATH@ -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
 
 # ,|template,)
-#   perl -i.bak -pe '
+#   @PERL_PATH@ -i.bak -pe '
 #      print "\n" . `git diff --cached --name-status -r`
 #       if /^#/ && $first++ == 0' "$1" ;;
 
index fd63b2d662dbcf98ec622a1ab754d041a559e3be..71ab04edc09be7aeefa1e8a0f609a974ffd55a9f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # An example hook script to blocks unannotated tags from entering.
-# Called by git-receive-pack with arguments: refname sha1-old sha1-new
+# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
 #
 # To enable this hook, rename this file to "update".
 #
@@ -64,7 +64,7 @@ zero="0000000000000000000000000000000000000000"
 if [ "$newrev" = "$zero" ]; then
        newrev_type=delete
 else
-       newrev_type=$(git-cat-file -t $newrev)
+       newrev_type=$(git cat-file -t $newrev)
 fi
 
 case "$refname","$newrev_type" in
index 2c87b72dff61f8394b3f1f32e21c1d936314ec2e..a5196d1be8fb59edf8062bef36d3a602e0812139 100644 (file)
@@ -1,4 +1,4 @@
-# git-ls-files --others --exclude-from=.git/info/exclude
+# git ls-files --others --exclude-from=.git/info/exclude
 # Lines that start with '#' are comments.
 # For a project mostly in C, the following would be a good set of
 # exclude patterns (uncomment them if you want to use them):
index 4f9c829c2df319e386b6b5d4f5c23818cc21c979..589f838f82b568195232ea81346d0049261b86b1 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include <pthread.h>
 
 #if defined(hpux) || defined(__hpux) || defined(_hpux)
 #  include <sys/pstat.h>
@@ -43,3 +44,18 @@ int online_cpus(void)
 
        return 1;
 }
+
+int init_recursive_mutex(pthread_mutex_t *m)
+{
+       pthread_mutexattr_t a;
+       int ret;
+
+       ret = pthread_mutexattr_init(&a);
+       if (!ret) {
+               ret = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
+               if (!ret)
+                       ret = pthread_mutex_init(m, &a);
+               pthread_mutexattr_destroy(&a);
+       }
+       return ret;
+}
index cce4b77bd6452e2ec589d8c0dc0e8156352dd67b..1727a03333b80f2a01ca029162a4b511480a86e8 100644 (file)
@@ -2,5 +2,6 @@
 #define THREAD_COMPAT_H
 
 extern int online_cpus(void);
+extern int init_recursive_mutex(pthread_mutex_t*);
 
 #endif /* THREAD_COMPAT_H */
index c29a9e067ff362063d6626e8e4d1e4466d63b8af..490cd5f6f4779cbff68405722b98e522cbeb3cde 100644 (file)
@@ -854,7 +854,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
 {
        struct stat st;
 
-       if (o->index_only || (!ce_skip_worktree(ce) && (o->reset || ce_uptodate(ce))))
+       if (o->index_only || (!((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) && (o->reset || ce_uptodate(ce))))
                return 0;
 
        if (!lstat(ce->name, &st)) {
index df992490d5f86b5eff2b87e90090b1ec576aae9a..38563daa3c7582ca87565886d74f16d11b292a57 100644 (file)
@@ -44,7 +44,9 @@ PATTERNS("pascal",
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
         "|<>|<=|>=|:=|\\.\\."
         "|[^[:space:]]|[\x80-\xff]+"),
-PATTERNS("php", "^[\t ]*((function|class).*)",
+PATTERNS("php",
+        "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
+        "^[\t ]*(class.*)$",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
index 10a6750795b287beabd50561402ffa8867f3e283..58201b6bcb8d362cffd1222bcb8cd77072c34cf5 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -3,11 +3,23 @@
  */
 #include "cache.h"
 
+static void try_to_free_builtin(size_t size)
+{
+       release_pack_memory(size, -1);
+}
+
+static void (*try_to_free_routine)(size_t size) = try_to_free_builtin;
+
+void set_try_to_free_routine(void (*routine)(size_t))
+{
+       try_to_free_routine = (routine) ? routine : try_to_free_builtin;
+}
+
 char *xstrdup(const char *str)
 {
        char *ret = strdup(str);
        if (!ret) {
-               release_pack_memory(strlen(str) + 1, -1);
+               try_to_free_routine(strlen(str) + 1);
                ret = strdup(str);
                if (!ret)
                        die("Out of memory, strdup failed");
@@ -21,7 +33,7 @@ void *xmalloc(size_t size)
        if (!ret && !size)
                ret = malloc(1);
        if (!ret) {
-               release_pack_memory(size, -1);
+               try_to_free_routine(size);
                ret = malloc(size);
                if (!ret && !size)
                        ret = malloc(1);
@@ -67,7 +79,7 @@ void *xrealloc(void *ptr, size_t size)
        if (!ret && !size)
                ret = realloc(ptr, 1);
        if (!ret) {
-               release_pack_memory(size, -1);
+               try_to_free_routine(size);
                ret = realloc(ptr, size);
                if (!ret && !size)
                        ret = realloc(ptr, 1);
@@ -83,7 +95,7 @@ void *xcalloc(size_t nmemb, size_t size)
        if (!ret && (!nmemb || !size))
                ret = calloc(1, 1);
        if (!ret) {
-               release_pack_memory(nmemb * size, -1);
+               try_to_free_routine(nmemb * size);
                ret = calloc(nmemb, size);
                if (!ret && (!nmemb || !size))
                        ret = calloc(1, 1);
index 8ca59a2d2abec0c9c4629cd4ae7340fcd79a0c7e..d44486c826ee46d258e88c5013d038243aad2756 100644 (file)
@@ -625,7 +625,9 @@ void wt_status_print(struct wt_status *s)
        if (s->show_untracked_files)
                wt_status_print_untracked(s);
        else if (s->commitable)
-                fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n");
+               fprintf(s->fp, "# Untracked files not listed%s\n",
+                       advice_status_hints
+                       ? " (use -u option to show untracked files)" : "");
 
        if (s->verbose)
                wt_status_print_verbose(s);
@@ -635,15 +637,22 @@ void wt_status_print(struct wt_status *s)
                else if (s->nowarn)
                        ; /* nothing */
                else if (s->workdir_dirty)
-                       printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
+                       printf("no changes added to commit%s\n",
+                               advice_status_hints
+                               ? " (use \"git add\" and/or \"git commit -a\")" : "");
                else if (s->untracked.nr)
-                       printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
+                       printf("nothing added to commit but untracked files present%s\n",
+                               advice_status_hints
+                               ? " (use \"git add\" to track)" : "");
                else if (s->is_initial)
-                       printf("nothing to commit (create/copy files and use \"git add\" to track)\n");
+                       printf("nothing to commit%s\n", advice_status_hints
+                               ? " (create/copy files and use \"git add\" to track)" : "");
                else if (!s->show_untracked_files)
-                       printf("nothing to commit (use -u to show untracked files)\n");
+                       printf("nothing to commit%s\n", advice_status_hints
+                               ? " (use -u to show untracked files)" : "");
                else
-                       printf("nothing to commit (working directory clean)\n");
+                       printf("nothing to commit%s\n", advice_status_hints
+                               ? " (working directory clean)" : "");
        }
 }
 
index ca5e3fbae8184e7114413ec65fe815e01ad6b2a8..cd2285de1cb1faa9f7c6c97dd22210f20bb046a3 100644 (file)
@@ -138,19 +138,20 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
 
 int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
                  xdiff_emit_consume_fn fn, void *consume_callback_data,
-                 xpparam_t const *xpp,
-                 xdemitconf_t const *xecfg, xdemitcb_t *xecb)
+                 xpparam_t const *xpp, xdemitconf_t const *xecfg)
 {
        int ret;
        struct xdiff_emit_state state;
+       xdemitcb_t ecb;
 
        memset(&state, 0, sizeof(state));
        state.consume = fn;
        state.consume_callback_data = consume_callback_data;
-       xecb->outf = xdiff_outf;
-       xecb->priv = &state;
+       memset(&ecb, 0, sizeof(ecb));
+       ecb.outf = xdiff_outf;
+       ecb.priv = &state;
        strbuf_init(&state.remainder, 0);
-       ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb);
+       ret = xdi_diff(mf1, mf2, xpp, xecfg, &ecb);
        strbuf_release(&state.remainder);
        return ret;
 }
index abba70c16bb31fae0df999241830d0c8df8bfbb3..49d1116fc34f536ab9358313522a25564dd1f6c3 100644 (file)
@@ -9,8 +9,7 @@ typedef void (*xdiff_emit_hunk_consume_fn)(void *, long, long, long);
 int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb);
 int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
                  xdiff_emit_consume_fn fn, void *consume_callback_data,
-                 xpparam_t const *xpp,
-                 xdemitconf_t const *xecfg, xdemitcb_t *xecb);
+                 xpparam_t const *xpp, xdemitconf_t const *xecfg);
 int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,
                   xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,
                   xpparam_t const *xpp, xdemitconf_t *xecfg);
index a71763ade835fd93ef291106298647408ada08e9..711048ea36dda1d814b395efa8bc69ab142425ca 100644 (file)
@@ -117,12 +117,14 @@ typedef struct s_xmparam {
        int level;
        int favor;
        int style;
+       const char *ancestor;   /* label for orig */
+       const char *file1;      /* label for mf1 */
+       const char *file2;      /* label for mf2 */
 } xmparam_t;
 
 #define DEFAULT_CONFLICT_MARKER_SIZE 7
 
-int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
-               mmfile_t *mf2, const char *name2,
+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
                xmparam_t const *xmp, mmbuffer_t *result);
 
 #ifdef __cplusplus
index 87cafa7021468d00a11c72dfdc1df05f1ede0fea..6d6fc1bc5e01be7305ec5101f43645a1dce69bd3 100644 (file)
@@ -145,12 +145,13 @@ static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 
 static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                              xdfenv_t *xe2, const char *name2,
+                             const char *name3,
                              int size, int i, int style,
                              xdmerge_t *m, char *dest, int marker_size)
 {
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
-       int j;
+       int marker3_size = (name3 ? strlen(name3) + 1 : 0);
 
        if (marker_size <= 0)
                marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
@@ -162,8 +163,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        if (!dest) {
                size += marker_size + 1 + marker1_size;
        } else {
-               for (j = 0; j < marker_size; j++)
-                       dest[size++] = '<';
+               memset(dest + size, '<', marker_size);
+               size += marker_size;
                if (marker1_size) {
                        dest[size] = ' ';
                        memcpy(dest + size + 1, name1, marker1_size - 1);
@@ -179,10 +180,15 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        if (style == XDL_MERGE_DIFF3) {
                /* Shared preimage */
                if (!dest) {
-                       size += marker_size + 1;
+                       size += marker_size + 1 + marker3_size;
                } else {
-                       for (j = 0; j < marker_size; j++)
-                               dest[size++] = '|';
+                       memset(dest + size, '|', marker_size);
+                       size += marker_size;
+                       if (marker3_size) {
+                               dest[size] = ' ';
+                               memcpy(dest + size + 1, name3, marker3_size - 1);
+                               size += marker3_size;
+                       }
                        dest[size++] = '\n';
                }
                size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
@@ -192,8 +198,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        if (!dest) {
                size += marker_size + 1;
        } else {
-               for (j = 0; j < marker_size; j++)
-                       dest[size++] = '=';
+               memset(dest + size, '=', marker_size);
+               size += marker_size;
                dest[size++] = '\n';
        }
 
@@ -203,8 +209,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        if (!dest) {
                size += marker_size + 1 + marker2_size;
        } else {
-               for (j = 0; j < marker_size; j++)
-                       dest[size++] = '>';
+               memset(dest + size, '>', marker_size);
+               size += marker_size;
                if (marker2_size) {
                        dest[size] = ' ';
                        memcpy(dest + size + 1, name2, marker2_size - 1);
@@ -217,6 +223,7 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
 
 static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                                 xdfenv_t *xe2, const char *name2,
+                                const char *ancestor_name,
                                 int favor,
                                 xdmerge_t *m, char *dest, int style,
                                 int marker_size)
@@ -229,6 +236,7 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
 
                if (m->mode == 0)
                        size = fill_conflict_hunk(xe1, name1, xe2, name2,
+                                                 ancestor_name,
                                                  size, i, style, m, dest,
                                                  marker_size);
                else if (m->mode & 3) {
@@ -398,11 +406,15 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
  *
  * returns < 0 on error, == 0 for no conflicts, else number of conflicts
  */
-static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
-               xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
-               xmparam_t const *xmp, mmbuffer_t *result) {
+static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
+               xdfenv_t *xe2, xdchange_t *xscr2,
+               xmparam_t const *xmp, mmbuffer_t *result)
+{
        xdmerge_t *changes, *c;
        xpparam_t const *xpp = &xmp->xpp;
+       const char *const ancestor_name = xmp->ancestor;
+       const char *const name1 = xmp->file1;
+       const char *const name2 = xmp->file2;
        int i0, i1, i2, chg0, chg1, chg2;
        int level = xmp->level;
        int style = xmp->style;
@@ -540,6 +552,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
        if (result) {
                int marker_size = xmp->marker_size;
                int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
+                                                ancestor_name,
                                                 favor, changes, NULL, style,
                                                 marker_size);
                result->ptr = xdl_malloc(size);
@@ -548,15 +561,16 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
                        return -1;
                }
                result->size = size;
-               xdl_fill_merge_buffer(xe1, name1, xe2, name2, favor, changes,
+               xdl_fill_merge_buffer(xe1, name1, xe2, name2,
+                                     ancestor_name, favor, changes,
                                      result->ptr, style, marker_size);
        }
        return xdl_cleanup_merge(changes);
 }
 
-int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
-               mmfile_t *mf2, const char *name2,
-               xmparam_t const *xmp, mmbuffer_t *result) {
+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
+               xmparam_t const *xmp, mmbuffer_t *result)
+{
        xdchange_t *xscr1, *xscr2;
        xdfenv_t xe1, xe2;
        int status;
@@ -591,8 +605,8 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
                memcpy(result->ptr, mf1->ptr, mf1->size);
                result->size = mf1->size;
        } else {
-               status = xdl_do_merge(&xe1, xscr1, name1,
-                                     &xe2, xscr2, name2,
+               status = xdl_do_merge(&xe1, xscr1,
+                                     &xe2, xscr2,
                                      xmp, result);
        }
        xdl_free_script(xscr1);