Merge branch 'da/p4merge-mktemp-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 25 Feb 2013 16:04:05 +0000 (08:04 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 25 Feb 2013 16:04:05 +0000 (08:04 -0800)
* da/p4merge-mktemp-fix:
p4merge: fix printf usage

177 files changed:
.gitignore
.mailmap
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/RelNotes/1.8.0.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.1.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.1.2.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.1.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.1.4.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.1.txt
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-bisect.txt
Documentation/git-bundle.txt
Documentation/git-checkout.txt
Documentation/git-commit-tree.txt
Documentation/git-config.txt
Documentation/git-cvsimport.txt
Documentation/git-diff.txt
Documentation/git-fast-import.txt
Documentation/git-for-each-ref.txt
Documentation/git-remote-helpers.txt [deleted file]
Documentation/git-remote-helpers.txto [new file with mode: 0644]
Documentation/git-remote-testgit.txt
Documentation/git-shortlog.txt
Documentation/git-svn.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitremote-helpers.txt [new file with mode: 0644]
Documentation/howto/maintain-git.txt
Documentation/howto/new-command.txt [new file with mode: 0644]
Documentation/mailmap.txt
Documentation/pt_BR/gittutorial.txt [deleted file]
Documentation/technical/api-allocation-growing.txt
Documentation/technical/api-command.txt [deleted file]
Documentation/technical/api-history-graph.txt
Documentation/technical/api-index-skel.txt
Documentation/technical/api-run-command.txt
Documentation/technical/api-string-list.txt
Documentation/technical/index-format.txt
Documentation/urls.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
INSTALL
Makefile
README
RelNotes
abspath.c
archive-tar.c
archive-zip.c
archive.c
attr.c
builtin.h
builtin/add.c
builtin/apply.c
builtin/branch.c
builtin/clean.c
builtin/clone.c
builtin/commit.c
builtin/fmt-merge-msg.c
builtin/help.c
builtin/merge-index.c
builtin/merge-tree.c
builtin/merge.c
builtin/shortlog.c
cache-tree.c
cache-tree.h
cache.h
combine-diff.c
compat/fnmatch/fnmatch.c
compat/nedmalloc/nedmalloc.c
config.c
configure.ac
contrib/completion/git-completion.bash
contrib/completion/git-completion.tcsh
contrib/completion/git-prompt.sh
contrib/remote-helpers/git-remote-hg
contrib/remote-helpers/test-hg-bidi.sh
contrib/stats/mailmap.pl
contrib/subtree/.gitignore
contrib/subtree/git-subtree.txt
contrib/vim/README
dir.c
editor.c
git-am.sh
git-compat-util.h
git-cvsimport.perl
git-difftool--helper.sh
git-mergetool.sh
git-p4.py
git-rebase--interactive.sh
git-send-email.perl
git-sh-setup.sh
gitweb/gitweb.perl
gpg-interface.c
graph.c
help.c
http-push.c
http.c
http.h
ident.c
imap-send.c
merge-blobs.c [new file with mode: 0644]
merge-blobs.h [new file with mode: 0644]
merge-file.c [deleted file]
merge-file.h [deleted file]
merge-recursive.c
parse-options.c
path.c
perl/Git.pm
perl/Git/SVN.pm
perl/Git/SVN/Log.pm
perl/Git/SVN/Prompt.pm
pretty.c
refs.c
remote-curl.c
remote.c
run-command.c
sequencer.c
setup.c
string-list.c
string-list.h
t/Makefile
t/lib-gettext.sh
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/lib-httpd/broken-smart-http.sh [new file with mode: 0755]
t/t0024-crlf-archive.sh
t/t0050-filesystem.sh
t/t0060-path-utils.sh
t/t0063-string-list.sh
t/t1020-subdirectory.sh
t/t1402-check-ref-format.sh
t/t1505-rev-parse-last.sh
t/t2203-add-intent.sh
t/t3404-rebase-interactive.sh
t/t3501-revert-cherry-pick.sh
t/t3506-cherry-pick-ff.sh
t/t3507-cherry-pick-conflict.sh
t/t3508-cherry-pick-many-commits.sh
t/t3510-cherry-pick-sequence.sh
t/t3600-rm.sh
t/t4014-format-patch.sh
t/t4038-diff-combined.sh
t/t4201-shortlog.sh
t/t4202-log.sh
t/t4300-merge-tree.sh
t/t5000-tar-tree.sh
t/t5002-archive-attr-pattern.sh [new file with mode: 0755]
t/t5003-archive-zip.sh [new file with mode: 0755]
t/t5003/infozip-symlinks.zip [new file with mode: 0644]
t/t5535-fetch-push-symref.sh [new file with mode: 0755]
t/t5551-http-fetch.sh
t/t5600-clone-fail-cleanup.sh
t/t6030-bisect-porcelain.sh
t/t7061-wtstatus-ignore.sh [new file with mode: 0755]
t/t7402-submodule-rebase.sh
t/t7505-prepare-commit-msg-hook.sh
t/t7512-status-help.sh
t/t9020-remote-svn.sh
t/t9200-git-cvsexportcommit.sh
t/t9502-gitweb-standalone-parse-output.sh
t/t9802-git-p4-filetype.sh
t/t9810-git-p4-rcs.sh
t/t9902-completion.sh
t/test-lib-functions.sh
t/test-lib.sh
t/test-terminal.perl
test-path-utils.c
test-string-list.c
transport.c
utf8.c
utf8.h
wrapper.c
wt-status.c
index f702415c12c5a4a66180f7ffd697347e5343ac4a..726db73450189ccd1ab6975ba9ca872f53a79c44 100644 (file)
@@ -3,6 +3,7 @@
 /GIT-LDFLAGS
 /GIT-GUI-VARS
 /GIT-PREFIX
+/GIT-PYTHON-VARS
 /GIT-SCRIPT-DEFINES
 /GIT-USER-AGENT
 /GIT-VERSION-FILE
index bcf4f8770f0751a61cf1c1b89a0d66cff559c54e..c7e86183001a00ad2105765708b5b59852ef6640 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -9,7 +9,9 @@ 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>
+Cheng Renquan <crquan@gmail.com>
 Chris Shoemaker <c.shoemaker@cox.net>
+Dan Johnson <computerdruid@gmail.com>
 Dana L. How <danahow@gmail.com>
 Dana L. How <how@deathvalley.cswitch.com>
 Daniel Barkalow <barkalow@iabervon.org>
@@ -18,14 +20,18 @@ 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>
+Eric S. Raymond <esr@thyrsus.com>
 Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com>
 Fredrik Kuivinen <freku045@student.liu.se>
+Frédéric Heitzmann <frederic.heitzmann@gmail.com>
 H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
 H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
 H. Peter Anvin <hpa@trantor.hos.anvin.org>
 Horst H. von Brand <vonbrand@inf.utfsm.cl>
 Ä°smail Dönmez <ismail@pardus.org.tr>
+Jakub NarÄ™bski <jnareb@gmail.com>
 Jay Soffian <jaysoffian+git@gmail.com>
+Jeff King <peff@peff.net> <peff@github.com>
 Joachim Berdal Haga <cjhaga@fys.uio.no>
 Johannes Sixt <j6t@kdbg.org> <johannes.sixt@telecom.at>
 Johannes Sixt <j6t@kdbg.org> <j.sixt@viscovery.net>
@@ -41,12 +47,21 @@ Junio C Hamano <gitster@pobox.com> <junio@hera.kernel.org>
 Junio C Hamano <gitster@pobox.com> <junio@kernel.org>
 Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
 Karl Hasselström <kha@treskal.com>
+Kevin Leung <kevinlsk@gmail.com>
 Kent Engstrom <kent@lysator.liu.se>
 Lars Doelle <lars.doelle@on-line ! de>
 Lars Doelle <lars.doelle@on-line.de>
 Li Hong <leehong@pku.edu.cn>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@woody.linux-foundation.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@g5.osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@evo.osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org>
+Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org.(none)>
 Lukas Sandström <lukass@etek.chalmers.se>
-Martin Langhoff <martin@laptop.org>
+Marc-André Lureau <marcandre.lureau@gmail.com>
+Mark Rada <marada@uwaterloo.ca>
+Martin Langhoff <martin@laptop.org> <martin@catalyst.net.nz>
 Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com>
 Michael Coleman <tutufan@gmail.com>
 Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
@@ -63,11 +78,13 @@ Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com>
 Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
 René Scharfe <rene.scharfe@lsrfire.ath.cx>
 Robert Fitzsimons <robfitz@273k.net>
+Robert Zeh <robert.a.zeh@gmail.com>
 Sam Vilain <sam@vilain.net>
 Santi Béjar <sbejar@gmail.com>
 Sean Estabrooks <seanlkml@sympatico.ca>
 Shawn O. Pearce <spearce@spearce.org>
 Steven Grimm <koreth@midwinter.com>
+Tay Ray Chuan <rctay89@gmail.com>
 Theodore Ts'o <tytso@mit.edu>
 Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
 Tony Luck <tony.luck@intel.com>
index 57da6aadeb8b4d65037035afaa269f391e989c38..69f7e9b76c3f9b87b7951fb0df6a9720edadeb3e 100644 (file)
@@ -112,6 +112,14 @@ For C programs:
 
  - We try to keep to at most 80 characters per line.
 
+ - We try to support a wide range of C compilers to compile git with,
+   including old ones. That means that you should not use C99
+   initializers, even if a lot of compilers grok it.
+
+ - Variables have to be declared at the beginning of the block.
+
+ - NULL pointers shall be written as NULL, not as 0.
+
  - When declaring pointers, the star sides with the variable
    name, i.e. "char *string", not "char* string" or
    "char * string".  This makes it easier to understand code
index 7df75d0b9deedcbb7332ccdb83607ecee2c5ea02..3c538e3de732f3810e5d18cae5396192b80d3c6c 100644 (file)
@@ -1,7 +1,7 @@
 MAN1_TXT= \
        $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
                $(wildcard git-*.txt)) \
-       gitk.txt gitweb.txt git.txt
+       gitk.txt gitweb.txt git.txt gitremote-helpers.txt
 MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \
        gitrepository-layout.txt gitweb.conf.txt
 MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \
@@ -13,7 +13,8 @@ MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
 MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
 MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
 
-DOC_HTML=$(MAN_HTML)
+OBSOLETE_HTML = git-remote-helpers.html
+DOC_HTML=$(MAN_HTML) $(OBSOLETE_HTML)
 
 ARTICLES = howto-index
 ARTICLES += everyday
@@ -21,6 +22,7 @@ ARTICLES += git-tools
 ARTICLES += git-bisect-lk2009
 # with their own formatting rules.
 SP_ARTICLES = user-manual
+SP_ARTICLES += howto/new-command
 SP_ARTICLES += howto/revert-branch-rebase
 SP_ARTICLES += howto/using-merge-subtree
 SP_ARTICLES += howto/using-signed-tag-in-pull-request
@@ -177,8 +179,6 @@ all: html man
 
 html: $(DOC_HTML)
 
-$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7): asciidoc.conf
-
 man: man1 man5 man7
 man1: $(DOC_MAN1)
 man5: $(DOC_MAN5)
@@ -256,12 +256,18 @@ clean:
        $(RM) $(cmds_txt) *.made
        $(RM) manpage-base-url.xsl
 
-$(MAN_HTML): %.html : %.txt
+$(MAN_HTML): %.html : %.txt asciidoc.conf
        $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
        $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
                $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
        mv $@+ $@
 
+$(OBSOLETE_HTML): %.html : %.txto asciidoc.conf
+       $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+       $(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
+               $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
+       mv $@+ $@
+
 manpage-base-url.xsl: manpage-base-url.xsl.in
        sed "s|@@MAN_BASE_URL@@|$(MAN_BASE_URL)|" $< > $@
 
@@ -269,7 +275,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in
        $(QUIET_XMLTO)$(RM) $@ && \
        $(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
 
-%.xml : %.txt
+%.xml : %.txt asciidoc.conf
        $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
        $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
                $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
@@ -285,7 +291,7 @@ technical/api-index.txt: technical/api-index-skel.txt \
        $(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh
 
 technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
-$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt
+$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt asciidoc.conf
        $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
                $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt
 
@@ -330,7 +336,7 @@ $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
 
 howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
        $(QUIET_GEN)$(RM) $@+ $@ && \
-       '$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \
+       '$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(wildcard howto/*.txt)) >$@+ && \
        mv $@+ $@
 
 $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
diff --git a/Documentation/RelNotes/1.8.0.3.txt b/Documentation/RelNotes/1.8.0.3.txt
new file mode 100644 (file)
index 0000000..92b1e4b
--- /dev/null
@@ -0,0 +1,14 @@
+Git v1.8.0.3 Release Notes
+==========================
+
+Fixes since v1.8.0.2
+--------------------
+
+ * "git log -p -S<string>" did not apply the textconv filter while
+   looking for the <string>.
+
+ * In the documentation, some invalid example e-mail addresses were
+   formatted into mailto: links.
+
+Also contains many documentation updates backported from the 'master'
+branch that is preparing for the upcoming 1.8.1 release.
diff --git a/Documentation/RelNotes/1.8.1.1.txt b/Documentation/RelNotes/1.8.1.1.txt
new file mode 100644 (file)
index 0000000..6cde07b
--- /dev/null
@@ -0,0 +1,87 @@
+Git 1.8.1.1 Release Notes
+=========================
+
+Fixes since v1.8.1
+------------------
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.
+
+ * When attempting to read the XDG-style $HOME/.config/git/config and
+   finding that $HOME/.config/git is a file, we gave a wrong error
+   message, instead of treating the case as "a custom config file does
+   not exist there" and moving on.
+
+ * After failing to create a temporary file using mkstemp(), failing
+   pathname was not reported correctly on some platforms.
+
+ * http transport was wrong to ask for the username when the
+   authentication is done by certificate identity.
+
+ * The behaviour visible to the end users was confusing, when they
+   attempt to kill a process spawned in the editor that was in turn
+   launched by Git with SIGINT (or SIGQUIT), as Git would catch that
+   signal and die.  We ignore these signals now.
+
+ * A child process that was killed by a signal (e.g. SIGINT) was
+   reported in an inconsistent way depending on how the process was
+   spawned by us, with or without a shell in between.
+
+ * After "git add -N" and then writing a tree object out of the
+   index, the cache-tree data structure got corrupted.
+
+ * "git apply" misbehaved when fixing whitespace breakages by removing
+   excess trailing blank lines in some corner cases.
+
+ * A tar archive created by "git archive" recorded a directory in a
+   way that made NetBSD's implementation of "tar" sometimes unhappy.
+
+ * When "git clone --separate-git-dir=$over_there" is interrupted, it
+   failed to remove the real location of the $GIT_DIR it created.
+   This was most visible when interrupting a submodule update.
+
+ * "git fetch --mirror" and fetch that uses other forms of refspec
+   with wildcard used to attempt to update a symbolic ref that match
+   the wildcard on the receiving end, which made little sense (the
+   real ref that is pointed at by the symbolic ref would be updated
+   anyway).  Symbolic refs no longer are affected by such a fetch.
+
+ * The "log --graph" codepath fell into infinite loop in some
+   corner cases.
+
+ * "git merge" started calling prepare-commit-msg hook like "git
+   commit" does some time ago, but forgot to pay attention to the exit
+   status of the hook.
+
+ * "git pack-refs" that ran in parallel to another process that
+   created new refs had a race that can lose new ones.
+
+ * When a line to be wrapped has a solid run of non space characters
+   whose length exactly is the wrap width, "git shortlog -w" failed
+   to add a newline after such a line.
+
+ * The way "git svn" asked for password using SSH_ASKPASS and
+   GIT_ASKPASS was not in line with the rest of the system.
+
+ * "gitweb", when sorting by age to show repositories with new
+   activities first, used to sort repositories with absolutely
+   nothing in it early, which was not very useful.
+
+ * "gitweb", when sorting by age to show repositories with new
+   activities first, used to sort repositories with absolutely
+   nothing in it early, which was not very useful.
+
+ * When autoconf is used, any build on a different commit always ran
+   "config.status --recheck" even when unnecessary.
+
+ * Some scripted programs written in Python did not get updated when
+   PYTHON_PATH changed.
+
+ * We have been carrying a translated and long-unmaintained copy of an
+   old version of the tutorial; removed.
+
+ * Portability issues in many self-test scripts have been addressed.
+
+
+Also contains other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.8.1.2.txt b/Documentation/RelNotes/1.8.1.2.txt
new file mode 100644 (file)
index 0000000..5ab7b18
--- /dev/null
@@ -0,0 +1,25 @@
+Git 1.8.1.2 Release Notes
+=========================
+
+Fixes since v1.8.1.1
+--------------------
+
+ * An element on GIT_CEILING_DIRECTORIES list that does not name the
+   real path to a directory (i.e. a symbolic link) could have caused
+   the GIT_DIR discovery logic to escape the ceiling.
+
+ * Command line completion for "tcsh" emitted an unwanted space
+   after completing a single directory name.
+
+ * Command line completion leaked an unnecessary error message while
+   looking for possible matches with paths in <tree-ish>.
+
+ * "git archive" did not record uncompressed size in the header when
+   streaming a zip archive, which confused some implementations of unzip.
+
+ * When users spelled "cc:" in lowercase in the fake "header" in the
+   trailer part, "git send-email" failed to pick up the addresses from
+   there. As e-mail headers field names are case insensitive, this
+   script should follow suit and treat "cc:" and "Cc:" the same way.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.3.txt b/Documentation/RelNotes/1.8.1.3.txt
new file mode 100644 (file)
index 0000000..681cb35
--- /dev/null
@@ -0,0 +1,47 @@
+Git 1.8.1.3 Release Notes
+=========================
+
+Fixes since v1.8.1.2
+--------------------
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.  The fix for this in 1.8.1.2 had
+   performance degradations.
+
+ * Command line completion code was inadvertently made incompatible with
+   older versions of bash by using a newer array notation.
+
+ * Scripts to test bash completion was inherently flaky as it was
+   affected by whatever random things the user may have on $PATH.
+
+ * A fix was added to the build procedure to work around buggy
+   versions of ccache broke the auto-generation of dependencies, which
+   unfortunately is still relevant because some people use ancient
+   distros.
+
+ * We used to stuff "user@" and then append what we read from
+   /etc/mailname to come up with a default e-mail ident, but a bug
+   lost the "user@" part.
+
+ * "git am" did not parse datestamp correctly from Hg generated patch,
+   when it is run in a locale outside C (or en).
+
+ * Attempt to "branch --edit-description" an existing branch, while
+   being on a detached HEAD, errored out.
+
+ * "git cherry-pick" did not replay a root commit to an unborn branch.
+
+ * We forgot to close the file descriptor reading from "gpg" output,
+   killing "git log --show-signature" on a long history.
+
+ * "git rebase --preserve-merges" lost empty merges in recent versions
+   of Git.
+
+ * Rebasing the history of superproject with change in the submodule
+   has been broken since v1.7.12.
+
+ * A failure to push due to non-ff while on an unborn branch
+   dereferenced a NULL pointer when showing an error message.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.4.txt b/Documentation/RelNotes/1.8.1.4.txt
new file mode 100644 (file)
index 0000000..22af1d1
--- /dev/null
@@ -0,0 +1,11 @@
+Git 1.8.1.4 Release Notes
+=========================
+
+Fixes since v1.8.1.3
+--------------------
+
+ * "git imap-send" talking over imaps:// did make sure it received a
+   valid certificate from the other end, but did not check if the
+   certificate matched the host it thought it was talking to.
+
+Also contains various documentation fixes.
index fec1a06ec96e13c0e8ec24dac171dd5911130793..d6f9555923ae900bd9ff04e8283b513a678c1395 100644 (file)
@@ -29,24 +29,17 @@ UI, Workflows & Features
 
  * Command-line completion scripts for tcsh and zsh have been added.
 
- * A new remote-helper interface for Mercurial has been added to
-   contrib/remote-helpers.
+ * "git-prompt" scriptlet (in contrib/completion) can be told to paint
+   pieces of the hints in the prompt string in colors.
+
+ * Some documentation pages that used to ship only in the plain text
+   format are now formatted in HTML as well.
 
  * We used to have a workaround for a bug in ancient "less" that
    causes it to exit without any output when the terminal is resized.
    The bug has been fixed in "less" version 406 (June 2007), and the
    workaround has been removed in this release.
 
- * Some documentation pages that used to ship only in the plain text
-   format are now formatted in HTML as well.
-
- * "git-prompt" scriptlet (in contrib/completion) can be told to paint
-   pieces of the hints in the prompt string in colors.
-
- * A new configuration variable "diff.context" can be used to
-   give the default number of context lines in the patch output, to
-   override the hardcoded default of 3 lines.
-
  * When "git checkout" checks out a branch, it tells the user how far
    behind (or ahead) the new branch is relative to the remote tracking
    branch it builds upon.  The message now also advises how to sync
@@ -60,13 +53,17 @@ UI, Workflows & Features
    API regression but it is expected that nobody will notice it in
    practice.
 
- * "git log -p -S<string>" now looks for the <string> after applying
-   the textconv filter (if defined); earlier it inspected the contents
-   of the blobs without filtering.
+ * A new configuration variable "diff.context" can be used to
+   give the default number of context lines in the patch output, to
+   override the hardcoded default of 3 lines.
 
  * "git format-patch" learned the "--notes=<ref>" option to give
    notes for the commit after the three-dash lines in its output.
 
+ * "git log -p -S<string>" now looks for the <string> after applying
+   the textconv filter (if defined); earlier it inspected the contents
+   of the blobs without filtering.
+
  * "git log --grep=<pcre>" learned to honor the "grep.patterntype"
    configuration set to "perl".
 
@@ -116,6 +113,9 @@ Foreign Interface
  * The remote helper interface to interact with subversion
    repositories (one of the GSoC 2012 projects) has been merged.
 
+ * A new remote-helper interface for Mercurial has been added to
+   contrib/remote-helpers.
+
  * The documentation for git(1) was pointing at a page at an external
    site for the list of authors that no longer existed.  The link has
    been updated to point at an alternative site.
index 3d8b2fe4d18875f8505b91850dd33ec79b122076..90133d8c3b2ea7ea8af55a2bac0876b10aff8f3e 100644 (file)
@@ -1,65 +1,5 @@
-Checklist (and a short version for the impatient):
-
-       Commits:
-
-       - make commits of logical units
-       - check for unnecessary whitespace with "git diff --check"
-         before committing
-       - do not check in commented out code or unneeded files
-       - the first line of the commit message should be a short
-         description (50 characters is the soft limit, see DISCUSSION
-         in git-commit(1)), and should skip the full stop
-       - the body should provide a meaningful commit message, which:
-         . explains the problem the change tries to solve, iow, what
-           is wrong with the current code without the change.
-         . justifies the way the change solves the problem, iow, why
-           the result with the change is better.
-         . alternate solutions considered but discarded, if any.
-       - describe changes in imperative mood, e.g. "make xyzzy do frotz"
-         instead of "[This patch] makes xyzzy do frotz" or "[I] changed
-         xyzzy to do frotz", as if you are giving orders to the codebase
-         to change its behaviour.
-       - try to make sure your explanation can be understood without
-         external resources. Instead of giving a URL to a mailing list
-         archive, summarize the relevant points of the discussion.
-       - add a "Signed-off-by: Your Name <you@example.com>" line to the
-         commit message (or just use the option "-s" when committing)
-         to confirm that you agree to the Developer's Certificate of Origin
-       - make sure that you have tests for the bug you are fixing
-       - make sure that the test suite passes after your commit
-
-       Patch:
-
-       - use "git format-patch -M" to create the patch
-       - do not PGP sign your patch
-       - do not attach your patch, but read in the mail
-         body, unless you cannot teach your mailer to
-         leave the formatting of the patch alone.
-       - be careful doing cut & paste into your mailer, not to
-         corrupt whitespaces.
-       - provide additional information (which is unsuitable for
-         the commit message) between the "---" and the diffstat
-       - if you change, add, or remove a command line option or
-         make some other user interface change, the associated
-         documentation should be updated as well.
-       - if your name is not writable in ASCII, make sure that
-         you send off a message in the correct encoding.
-       - send the patch to the list (git@vger.kernel.org) and the
-         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:
-
-I started reading over the SubmittingPatches document for Linux
-kernel, primarily because I wanted to have a document similar to
-it for the core GIT to make sure people understand what they are
-doing when they write "Signed-off-by" line.
-
-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.
+Here are some guidelines for people who want to contribute their code
+to this software.
 
 (0) Decide what to base your work on.
 
@@ -86,6 +26,10 @@ change is relevant to.
    wait until some of the dependent topics graduate to 'master', and
    rebase your work.
 
+ - Some parts of the system have dedicated maintainers with their own
+   repositories (see the section "Subsystems" below).  Changes to
+   these parts should be based on their trees.
+
 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.
@@ -113,26 +57,53 @@ change, the approach taken by the change, and if relevant how this
 differs substantially from the prior version, are all good things
 to have.
 
+Make sure that you have tests for the bug you are fixing.
+
+When adding a new feature, make sure that you have new tests to show
+the feature triggers the new behaviour when it should, and to show the
+feature does not trigger when it shouldn't.  Also make sure that the
+test suite passes after your commit.  Do not forget to update the
+documentation to describe the updated behaviour.
+
 Oh, another thing.  I am picky about whitespaces.  Make sure your
 changes do not trigger errors with the sample pre-commit hook shipped
 in templates/hooks--pre-commit.  To help ensure this does not happen,
 run git diff --check on your changes before you commit.
 
 
-(1a) Try to be nice to older C compilers
+(2) Describe your changes well.
+
+The first line of the commit message should be a short description (50
+characters is the soft limit, see DISCUSSION in git-commit(1)), and
+should skip the full stop.  It is also conventional in most cases to
+prefix the first line with "area: " where the area is a filename or
+identifier for the general area of the code being modified, e.g.
+
+  . archive: ustar header checksum is computed unsigned
+  . git-cherry-pick.txt: clarify the use of revision range notation
+
+If in doubt which identifier to use, run "git log --no-merges" on the
+files you are modifying to see the current conventions.
 
-We try to support a wide range of C compilers to compile
-git with. That means that you should not use C99 initializers, even
-if a lot of compilers grok it.
+The body should provide a meaningful commit message, which:
 
-Also, variables have to be declared at the beginning of the block
-(you can check this with gcc, using the -Wdeclaration-after-statement
-option).
+  . explains the problem the change tries to solve, iow, what is wrong
+    with the current code without the change.
 
-Another thing: NULL pointers shall be written as NULL, not as 0.
+  . justifies the way the change solves the problem, iow, why the
+    result with the change is better.
 
+  . alternate solutions considered but discarded, if any.
 
-(2) Generate your patch using git tools out of your commits.
+Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
+instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
+to do frotz", as if you are giving orders to the codebase to change
+its behaviour.  Try to make sure your explanation can be understood
+without external resources. Instead of giving a URL to a mailing list
+archive, summarize the relevant points of the discussion.
+
+
+(3) Generate your patch using git tools out of your commits.
 
 git based diff tools generate unidiff which is the preferred format.
 
@@ -140,22 +111,27 @@ You do not have to be afraid to use -M option to "git diff" or
 "git format-patch", if your patch involves file renames.  The
 receiving end can handle them just fine.
 
-Please make sure your patch does not include any extra files
-which do not belong in a patch submission.  Make sure to review
+Please make sure your patch does not add commented out debugging code,
+or include any extra files which do not relate to what your patch
+is trying to achieve. Make sure to review
 your patch after generating it, to ensure accuracy.  Before
 sending out, please make sure it cleanly applies to the "master"
 branch head.  If you are preparing a work based on "next" branch,
 that is fine, but please mark it as such.
 
 
-(3) Sending your patches.
+(4) Sending your patches.
 
 People on the git mailing list need to be able to read and
 comment on the changes you are submitting.  It is important for
 a developer to be able to "quote" your changes, using standard
 e-mail tools, so that they may comment on specific portions of
 your code.  For this reason, all patches should be submitted
-"inline".  WARNING: Be wary of your MUAs word-wrap
+"inline".  If your log message (including your name on the
+Signed-off-by line) is not writable in ASCII, make sure that
+you send off a message in the correct encoding.
+
+WARNING: Be wary of your MUAs word-wrap
 corrupting your patch.  Do not cut-n-paste your patch; you can
 lose tabs that way if you are not careful.
 
@@ -208,19 +184,25 @@ 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.
 
-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
+Send your patch with "To:" set to the mailing list, with "cc:" listing
 people who are involved in the area you are touching (the output from
 "git blame $path" and "git shortlog --no-merges $path" would help to
-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.
+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 [*1*] and "cc:" the
+list [*2*] for inclusion.
+
+Do not forget to add trailers such as "Acked-by:", "Reviewed-by:" and
+"Tested-by:" lines as necessary to credit people who helped your
+patch.
 
+    [Addresses]
+     *1* The current maintainer: gitster@pobox.com
+     *2* The mailing list: git@vger.kernel.org
 
-(4) Sign your work
+
+(5) Sign your work
 
 To improve tracking of who did what, we've borrowed the
 "sign-off" procedure from the Linux kernel project on patches
@@ -290,6 +272,26 @@ If you like, you can put extra tags at the end:
 You can also create your own tag or use one that's in common usage
 such as "Thanks-to:", "Based-on-patch-by:", or "Mentored-by:".
 
+------------------------------------------------
+Subsystems with dedicated maintainers
+
+Some parts of the system have dedicated maintainers with their own
+repositories.
+
+ - git-gui/ comes from git-gui project, maintained by Pat Thoyts:
+
+        git://repo.or.cz/git-gui.git
+
+ - gitk-git/ comes from Paul Mackerras's gitk project:
+
+        git://ozlabs.org/~paulus/gitk
+
+ - po/ comes from the localization coordinator, Jiang Xin:
+
+       https://github.com/git-l10n/git-po/
+
+Patches to these parts should be based on their trees.
+
 ------------------------------------------------
 An ideal patch flow
 
index bf8f911e1ffe7820a8e903ec669c690d39612150..dbb2faf602552f9d898faa1c1a525d041214082c 100644 (file)
@@ -168,7 +168,7 @@ advice.*::
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwriting local changes.
        resolveConflict::
-               Advices shown by various commands when conflicts
+               Advice shown by various commands when conflicts
                prevent the operation from being performed.
        implicitIdentity::
                Advice on how to set your identity configuration when
@@ -1351,6 +1351,12 @@ help.autocorrect::
        value is 0 - the command will be just shown but not executed.
        This is the default.
 
+help.htmlpath::
+       Specify the path where the HTML documentation resides. File system paths
+       and URLs are supported. HTML pages will be prefixed with this path when
+       help is displayed in the 'web' format. This defaults to the documentation
+       path of your Git installation.
+
 http.proxy::
        Override the HTTP proxy, normally configured using the 'http_proxy',
        'https_proxy', and 'all_proxy' environment variables (see
index b4d6476ac898db8ff99ab3639efce08050ef71c4..6e98bdf1490a0a5718dd14a4c2d8b2baaee7383e 100644 (file)
@@ -57,14 +57,11 @@ endif::git-pull[]
 ifndef::git-pull[]
 -t::
 --tags::
-       Most of the tags are fetched automatically as branch
-       heads are downloaded, but tags that do not point at
-       objects reachable from the branch heads that are being
-       tracked will not be fetched by this mechanism.  This
-       flag lets all tags and their associated objects be
-       downloaded. The default behavior for a remote may be
-       specified with the remote.<name>.tagopt setting. See
-       linkgit:git-config[1].
+       This is a short-hand for giving "refs/tags/*:refs/tags/*"
+       refspec from the command line, to ask all tags to be fetched
+       and stored locally.  Because this acts as an explicit
+       refspec, the default refspecs (configured with the
+       remote.$name.fetch variable) are overridden and not used.
 
 --recurse-submodules[=yes|on-demand|no]::
        This option controls if and under what conditions new commits of
index fd9e36b99f5506964ac8352b82bb7af05551a523..d0cdb07844b8361debc1565f11b11b813fe81c57 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
          [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
          [--refresh] [--ignore-errors] [--ignore-missing] [--]
-         [<filepattern>...]
+         [<pathspec>...]
 
 DESCRIPTION
 -----------
@@ -49,7 +49,7 @@ commit.
 
 OPTIONS
 -------
-<filepattern>...::
+<pathspec>...::
        Files to add content from.  Fileglobs (e.g. `*.c`) can
        be given to add all matching files.  Also a
        leading directory name (e.g. `dir` to add `dir/file1`
@@ -100,20 +100,20 @@ apply to the index. See EDITING PATCHES below.
 
 -u::
 --update::
-       Only match <filepattern> against already tracked files in
+       Only match <pathspec> against already tracked files in
        the index rather than the working tree. That means that it
        will never stage new files, but that it will stage modified
        new contents of tracked files and that it will remove files
        from the index if the corresponding files in the working tree
        have been removed.
 +
-If no <filepattern> is given, default to "."; in other words,
+If no <pathspec> is given, default to "."; in other words,
 update all tracked files in the current directory and its
 subdirectories.
 
 -A::
 --all::
-       Like `-u`, but match <filepattern> against files in the
+       Like `-u`, but match <pathspec> against files in the
        working tree in addition to the index. That means that it
        will find new files as well as staging modified content and
        removing files that are no longer in the working tree.
index e4f46bc18dba1e55da83e4af76b8a7f30a7f40be..038514b51e02d4429df7bb517367e63373a59ecb 100644 (file)
@@ -83,7 +83,7 @@ Bisect reset
 ~~~~~~~~~~~~
 
 After a bisect session, to clean up the bisection state and return to
-the original HEAD, issue the following command:
+the original HEAD (i.e., to quit bisecting), issue the following command:
 
 ------------------------------------------------
 $ git bisect reset
@@ -284,6 +284,7 @@ EXAMPLES
 ------------
 $ git bisect start HEAD v1.2 --      # HEAD is bad, v1.2 is good
 $ git bisect run make                # "make" builds the app
+$ git bisect reset                   # quit the bisect session
 ------------
 
 * Automatically bisect a test failure between origin and HEAD:
@@ -291,6 +292,7 @@ $ git bisect run make                # "make" builds the app
 ------------
 $ git bisect start HEAD origin --    # HEAD is bad, origin is good
 $ git bisect run make test           # "make test" builds and tests
+$ git bisect reset                   # quit the bisect session
 ------------
 
 * Automatically bisect a broken test case:
@@ -302,6 +304,7 @@ make || exit 125                     # this skips broken builds
 ~/check_test_case.sh                 # does the test case pass?
 $ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
 $ git bisect run ~/test.sh
+$ git bisect reset                   # quit the bisect session
 ------------
 +
 Here we use a "test.sh" custom script. In this script, if "make"
@@ -351,6 +354,7 @@ use `git cherry-pick` instead of `git merge`.)
 ------------
 $ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
 $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
+$ git bisect reset                   # quit the bisect session
 ------------
 +
 This shows that you can do without a run script if you write the test
@@ -368,6 +372,7 @@ $ git bisect run sh -c '
        rm -f tmp.$$
        test $rc = 0'
 
+$ git bisect reset                   # quit the bisect session
 ------------
 +
 In this case, when 'git bisect run' finishes, bisect/bad will refer to a commit that
index 16a6b0acebc7e15bfae0850d6d6c716fd5a32eaa..bc023cc5f3bb6be8cd664ec6a74743f46b396283 100644 (file)
@@ -112,13 +112,12 @@ machineA$ git bundle create file.bundle master
 machineA$ git tag -f lastR2bundle master
 ----------------
 
-Then you transfer file.bundle to the target machine B. If you are creating
-the repository on machine B, then you can clone from the bundle as if it
-were a remote repository instead of creating an empty repository and then
-pulling or fetching objects from the bundle:
+Then you transfer file.bundle to the target machine B. Because this
+bundle does not require any existing object to be extracted, you can
+create a new repository on machine B by cloning from it:
 
 ----------------
-machineB$ git clone /home/me/tmp/file.bundle R2
+machineB$ git clone -b master /home/me/tmp/file.bundle R2
 ----------------
 
 This will define a remote called "origin" in the resulting repository that
index 7958a4700642270ad3f801e314cf870331cf4512..6f04d22f5e15ea0805fb44c9c856952d759bc050 100644 (file)
@@ -21,18 +21,34 @@ or the specified tree.  If no paths are given, 'git checkout' will
 also update `HEAD` to set the specified branch as the current
 branch.
 
-'git checkout' [<branch>]::
+'git checkout' <branch>::
+       To prepare for working on <branch>, switch to it by updating
+       the index and the files in the working tree, and by pointing
+       HEAD at the branch. Local modifications to the files in the
+       working tree are kept, so that they can be committed to the
+       <branch>.
++
+If <branch> is not found but there does exist a tracking branch in
+exactly one remote (call it <remote>) with a matching name, treat as
+equivalent to
++
+------------
+$ git checkout -b <branch> --track <remote>/<branch>
+------------
++
+You could omit <branch>, in which case the command degenerates to
+"check out the current branch", which is a glorified no-op with a
+rather expensive side-effects to show only the tracking information,
+if exists, for the current branch.
+
 'git checkout' -b|-B <new_branch> [<start point>]::
-'git checkout' [--detach] [<commit>]::
 
-       This form switches branches by updating the index, working
-       tree, and HEAD to reflect the specified branch or commit.
-+
-If `-b` is given, a new branch is created as if linkgit:git-branch[1]
-were called and then checked out; in this case you can
-use the `--track` or `--no-track` options, which will be passed to
-'git branch'.  As a convenience, `--track` without `-b` implies branch
-creation; see the description of `--track` below.
+       Specifying `-b` causes a new branch to be created as if
+       linkgit:git-branch[1] were called and then checked out.  In
+       this case you can use the `--track` or `--no-track` options,
+       which will be passed to 'git branch'.  As a convenience,
+       `--track` without `-b` implies branch creation; see the
+       description of `--track` below.
 +
 If `-B` is given, <new_branch> is created if it doesn't exist; otherwise, it
 is reset. This is the transactional equivalent of
@@ -45,6 +61,21 @@ $ git checkout <branch>
 that is to say, the branch is not reset/created unless "git checkout" is
 successful.
 
+'git checkout' --detach [<branch>]::
+'git checkout' <commit>::
+
+       Prepare to work on top of <commit>, by detaching HEAD at it
+       (see "DETACHED HEAD" section), and updating the index and the
+       files in the working tree.  Local modifications to the files
+       in the working tree are kept, so that the resulting working
+       tree will be the state recorded in the commit plus the local
+       modifications.
++
+Passing `--detach` forces this behavior in the case of a <branch> (without
+the option, giving a branch name to the command would check out the branch,
+instead of detaching HEAD at it), or the current commit,
+if no <branch> is specified.
+
 'git checkout' [-p|--patch] [<tree-ish>] [--] <pathspec>...::
 
        When <paths> or `--patch` are given, 'git checkout' does *not*
index 6d5a04c83b6461396b44b3972a539eaae6368a19..a22116951527e4181d85ed23acb029f6920ee1ff 100644 (file)
@@ -72,13 +72,13 @@ if set:
        GIT_COMMITTER_NAME
        GIT_COMMITTER_EMAIL
        GIT_COMMITTER_DATE
-       EMAIL
 
 (nb "<", ">" and "\n"s are stripped)
 
 In case (some of) these environment variables are not set, the information
 is taken from the configuration items user.name and user.email, or, if not
-present, system user name and the hostname used for outgoing mail (taken
+present, the environment variable EMAIL, or, if that is not set,
+system user name and the hostname used for outgoing mail (taken
 from `/etc/mailname` and falling back to the fully qualified hostname when
 that file does not exist).
 
index eaea0791657386469e448def614b949c0a1f45e9..9ae2508f3fb79b9da5fb4481a4fe2120f4a082b1 100644 (file)
@@ -240,6 +240,10 @@ GIT_CONFIG::
        Using the "--global" option forces this to ~/.gitconfig. Using the
        "--system" option forces this to $(prefix)/etc/gitconfig.
 
+GIT_CONFIG_NOSYSTEM::
+       Whether to skip reading settings from the system-wide
+       $(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
+
 See also <<FILES>>.
 
 
index 98d9881d7e891e4728c09f6536c3506b3688d145..f059ea94daf72dc66c9e04455b4fdbb235875c52 100644 (file)
@@ -18,6 +18,12 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
+*WARNING:* `git cvsimport` uses cvsps version 2, which is considered
+deprecated; it does not work with cvsps version 3 and later.  If you are
+performing a one-shot import of a CVS repository consider using
+link:http://cvs2svn.tigris.org/cvs2git.html[cvs2git] or
+link:https://github.com/BartMassey/parsecvs[parsecvs].
+
 Imports a CVS repository into git. It will either create a new
 repository, or incrementally import into an existing one.
 
@@ -213,11 +219,9 @@ Problems related to tags:
 * Multiple tags on the same revision are not imported.
 
 If you suspect that any of these issues may apply to the repository you
-want to import consider using these alternative tools which proved to be
-more stable in practice:
+want to imort, consider using cvs2git:
 
-* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
-* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
+* cvs2git (part of cvs2svn), `http://subversion.apache.org/`
 
 GIT
 ---
index f8d0819113c52ac7c6388ec27eb96083a8c86d4a..f8c06013f3588a96e66d08265afe8131f054b7ff 100644 (file)
@@ -12,6 +12,7 @@ SYNOPSIS
 'git diff' [options] [<commit>] [--] [<path>...]
 'git diff' [options] --cached [<commit>] [--] [<path>...]
 'git diff' [options] <commit> <commit> [--] [<path>...]
+'git diff' [options] <blob> <blob>
 'git diff' [options] [--no-index] [--] <path> <path>
 
 DESCRIPTION
@@ -55,6 +56,11 @@ directories. This behavior can be forced by --no-index.
        This is to view the changes between two arbitrary
        <commit>.
 
+'git diff' [options] <blob> <blob>::
+
+       This form is to view the differences between the raw
+       contents of two blob objects.
+
 'git diff' [--options] <commit>..<commit> [--] [<path>...]::
 
        This is synonymous to the previous form.  If <commit> on
@@ -72,8 +78,7 @@ directories. This behavior can be forced by --no-index.
 Just in case if you are doing something exotic, it should be
 noted that all of the <commit> in the above description, except
 in the last two forms that use ".." notations, can be any
-<tree>.  The third form ('git diff <commit> <commit>') can also
-be used to compare two <blob> objects.
+<tree>.
 
 For a more complete list of ways to spell <commit>, see
 "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
index d1844ead4a4883cc31447c20763b61091f66ed8e..bf1a02a80d5f4a61f5bbd0d826ae7df3bce58911 100644 (file)
@@ -33,38 +33,46 @@ the frontend program in use.
 
 OPTIONS
 -------
---date-format=<fmt>::
-       Specify the type of dates the frontend will supply to
-       fast-import within `author`, `committer` and `tagger` commands.
-       See ``Date Formats'' below for details about which formats
-       are supported, and their syntax.
-
--- done::
-       Terminate with error if there is no 'done' command at the
-       end of the stream.
 
 --force::
        Force updating modified existing branches, even if doing
        so would cause commits to be lost (as the new commit does
        not contain the old commit).
 
---max-pack-size=<n>::
-       Maximum size of each output packfile.
-       The default is unlimited.
+--quiet::
+       Disable all non-fatal output, making fast-import silent when it
+       is successful.  This option disables the output shown by
+       \--stats.
 
---big-file-threshold=<n>::
-       Maximum size of a blob that fast-import will attempt to
-       create a delta for, expressed in bytes.  The default is 512m
-       (512 MiB).  Some importers may wish to lower this on systems
-       with constrained memory.
+--stats::
+       Display some basic statistics about the objects fast-import has
+       created, the packfiles they were stored into, and the
+       memory used by fast-import during this run.  Showing this output
+       is currently the default, but can be disabled with \--quiet.
 
---depth=<n>::
-       Maximum delta depth, for blob and tree deltification.
-       Default is 10.
+Options for Frontends
+~~~~~~~~~~~~~~~~~~~~~
 
---active-branches=<n>::
-       Maximum number of branches to maintain active at once.
-       See ``Memory Utilization'' below for details.  Default is 5.
+--cat-blob-fd=<fd>::
+       Write responses to `cat-blob` and `ls` queries to the
+       file descriptor <fd> instead of `stdout`.  Allows `progress`
+       output intended for the end-user to be separated from other
+       output.
+
+--date-format=<fmt>::
+       Specify the type of dates the frontend will supply to
+       fast-import within `author`, `committer` and `tagger` commands.
+       See ``Date Formats'' below for details about which formats
+       are supported, and their syntax.
+
+--done::
+       Terminate with error if there is no `done` command at the end of
+       the stream.  This option might be useful for detecting errors
+       that cause the frontend to terminate before it has started to
+       write a stream.
+
+Locations of Marks Files
+~~~~~~~~~~~~~~~~~~~~~~~~
 
 --export-marks=<file>::
        Dumps the internal marks table to <file> when complete.
@@ -87,31 +95,33 @@ OPTIONS
        Like --import-marks but instead of erroring out, silently
        skips the file if it does not exist.
 
---relative-marks::
+--[no-]relative-marks::
        After specifying --relative-marks the paths specified
        with --import-marks= and --export-marks= are relative
        to an internal directory in the current repository.
        In git-fast-import this means that the paths are relative
        to the .git/info/fast-import directory. However, other
        importers may use a different location.
++
+Relative and non-relative marks may be combined by interweaving
+--(no-)-relative-marks with the --(import|export)-marks= options.
 
---no-relative-marks::
-       Negates a previous --relative-marks. Allows for combining
-       relative and non-relative marks by interweaving
-       --(no-)-relative-marks with the --(import|export)-marks=
-       options.
+Performance and Compression Tuning
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
---cat-blob-fd=<fd>::
-       Write responses to `cat-blob` and `ls` queries to the
-       file descriptor <fd> instead of `stdout`.  Allows `progress`
-       output intended for the end-user to be separated from other
-       output.
+--active-branches=<n>::
+       Maximum number of branches to maintain active at once.
+       See ``Memory Utilization'' below for details.  Default is 5.
 
---done::
-       Require a `done` command at the end of the stream.
-       This option might be useful for detecting errors that
-       cause the frontend to terminate before it has started to
-       write a stream.
+--big-file-threshold=<n>::
+       Maximum size of a blob that fast-import will attempt to
+       create a delta for, expressed in bytes.  The default is 512m
+       (512 MiB).  Some importers may wish to lower this on systems
+       with constrained memory.
+
+--depth=<n>::
+       Maximum delta depth, for blob and tree deltification.
+       Default is 10.
 
 --export-pack-edges=<file>::
        After creating a packfile, print a line of data to
@@ -122,16 +132,9 @@ OPTIONS
        as these commits can be used as edge points during calls
        to 'git pack-objects'.
 
---quiet::
-       Disable all non-fatal output, making fast-import silent when it
-       is successful.  This option disables the output shown by
-       \--stats.
-
---stats::
-       Display some basic statistics about the objects fast-import has
-       created, the packfiles they were stored into, and the
-       memory used by fast-import during this run.  Showing this output
-       is currently the default, but can be disabled with \--quiet.
+--max-pack-size=<n>::
+       Maximum size of each output packfile.
+       The default is unlimited.
 
 
 Performance
@@ -427,7 +430,7 @@ they made it.
 
 Here `<name>` is the person's display name (for example
 ``Com M Itter'') and `<email>` is the person's email address
-(``cm@example.com'').  `LT` and `GT` are the literal less-than (\x3c)
+(``\cm@example.com'').  `LT` and `GT` are the literal less-than (\x3c)
 and greater-than (\x3e) symbols.  These are required to delimit
 the email address from the other fields in the line.  Note that
 `<name>` and `<email>` are free-form and may contain any sequence
index db55a4e0bbc524c20f08e6862daaa97dd1785b71..f2e08d11c19cf127c5f7d484b0c3d66fc475d547 100644 (file)
@@ -117,7 +117,7 @@ returns an empty string instead.
 
 As a special case for the date-type fields, you may specify a format for
 the date by adding one of `:default`, `:relative`, `:short`, `:local`,
-`:iso8601` or `:rfc2822` to the end of the fieldname; e.g.
+`:iso8601`, `:rfc2822` or `:raw` to the end of the fieldname; e.g.
 `%(taggerdate:relative)`.
 
 
diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt
deleted file mode 100644 (file)
index 6d696e0..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-git-remote-helpers(1)
-=====================
-
-NAME
-----
-git-remote-helpers - Helper programs to interact with remote repositories
-
-SYNOPSIS
---------
-[verse]
-'git remote-<transport>' <repository> [<URL>]
-
-DESCRIPTION
------------
-
-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
-uses to determine what other commands the helper will accept.  Those
-other commands can be used to discover and update remote refs,
-transport objects between the object database and the remote repository,
-and update the local object store.
-
-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.
-The 'GIT_DIR' environment variable is set up for the remote helper
-and can be used to determine where to store additional data or from
-which directory to invoke auxiliary git commands.
-
-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.
-
-INPUT FORMAT
-------------
-
-Git sends the remote helper a list of commands on standard input, one
-per line.  The first command is always the 'capabilities' command, in
-response to which the remote helper must print a list of the
-capabilities it supports (see below) followed by a blank line.  The
-response to the capabilities command determines what commands Git uses
-in the remainder of the command stream.
-
-The command stream is terminated by a blank line.  In some cases
-(indicated in the documentation of the relevant commands), this blank
-line is followed by a payload in some other protocol (e.g., the pack
-protocol), while in others it indicates the end of input.
-
-Capabilities
-~~~~~~~~~~~~
-
-Each remote helper is expected to support only a subset of commands.
-The operations a helper supports are declared to git in the response
-to the `capabilities` command (see COMMANDS, below).
-
-In the following, we list all defined capabilities and for
-each we list which commands a helper with that capability
-must provide.
-
-Capabilities for Pushing
-^^^^^^^^^^^^^^^^^^^^^^^^
-'connect'::
-       Can attempt to connect to 'git receive-pack' (for pushing),
-       'git upload-pack', etc for communication using
-       git's native packfile protocol. This
-       requires a bidirectional, full-duplex connection.
-+
-Supported commands: 'connect'.
-
-'push'::
-       Can discover remote refs and push local commits and the
-       history leading up to them to new or existing remote refs.
-+
-Supported commands: 'list for-push', 'push'.
-
-'export'::
-       Can discover remote refs and push specified objects from a
-       fast-import stream to remote refs.
-+
-Supported commands: 'list for-push', 'export'.
-
-If a helper advertises 'connect', git will use it if possible and
-fall back to another capability if the helper requests so when
-connecting (see the 'connect' command under COMMANDS).
-When choosing between 'push' and 'export', git prefers 'push'.
-Other frontends may have some other order of preference.
-
-
-Capabilities for Fetching
-^^^^^^^^^^^^^^^^^^^^^^^^^
-'connect'::
-       Can try to connect to 'git upload-pack' (for fetching),
-       'git receive-pack', etc for communication using the
-       git's native packfile protocol. This
-       requires a bidirectional, full-duplex connection.
-+
-Supported commands: 'connect'.
-
-'fetch'::
-       Can discover remote refs and transfer objects reachable from
-       them to the local object store.
-+
-Supported commands: 'list', 'fetch'.
-
-'import'::
-       Can discover remote refs and output objects reachable from
-       them as a stream in fast-import format.
-+
-Supported commands: 'list', 'import'.
-
-If a helper advertises 'connect', git will use it if possible and
-fall back to another capability if the helper requests so when
-connecting (see the 'connect' command under COMMANDS).
-When choosing between 'fetch' and 'import', git prefers 'fetch'.
-Other frontends may have some other order of preference.
-
-Miscellaneous capabilities
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-'option'::
-       For specifying settings like `verbosity` (how much output to
-       write to stderr) and `depth` (how much history is wanted in the
-       case of a shallow clone) that affect how other commands are
-       carried out.
-
-'refspec' <refspec>::
-       This modifies the 'import' capability, allowing the produced
-       fast-import stream to modify refs in a private namespace
-       instead of writing to refs/heads or refs/remotes directly.
-       It is recommended that all importers providing the 'import'
-       capability use this.
-+
-A helper advertising the capability
-`refspec refs/heads/*:refs/svn/origin/branches/*`
-is saying that, when it is asked to `import refs/heads/topic`, the
-stream it outputs will update the `refs/svn/origin/branches/topic`
-ref.
-+
-This capability can be advertised multiple times.  The first
-applicable refspec takes precedence.  The left-hand of refspecs
-advertised with this capability must cover all refs reported by
-the list command.  If no 'refspec' capability is advertised,
-there is an implied `refspec *:*`.
-
-'bidi-import'::
-       This modifies the 'import' capability.
-       The fast-import commands 'cat-blob' and 'ls' can be used by remote-helpers
-       to retrieve information about blobs and trees that already exist in
-       fast-import's memory. This requires a channel from fast-import to the
-       remote-helper.
-       If it is advertised in addition to "import", git establishes a pipe from
-       fast-import to the remote-helper's stdin.
-       It follows that git and fast-import are both connected to the
-       remote-helper's stdin. Because git can send multiple commands to
-       the remote-helper it is required that helpers that use 'bidi-import'
-       buffer all 'import' commands of a batch before sending data to fast-import.
-       This is to prevent mixing commands and fast-import responses on the
-       helper's stdin.
-
-'export-marks' <file>::
-       This modifies the 'export' capability, instructing git to dump the
-       internal marks table to <file> when complete. For details,
-       read up on '--export-marks=<file>' in linkgit:git-fast-export[1].
-
-'import-marks' <file>::
-       This modifies the 'export' capability, instructing git to load the
-       marks specified in <file> before processing any input. For details,
-       read up on '--import-marks=<file>' in linkgit:git-fast-export[1].
-
-
-
-
-COMMANDS
---------
-
-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 '*',
-       which marks them mandatory for git versions using the remote
-       helper to understand. Any unknown mandatory capability is a
-       fatal error.
-+
-Support for this command is mandatory.
-
-'list'::
-       Lists the refs, one per line, in the format "<value> <name>
-       [<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. The list ends
-       with a blank line.
-+
-See REF LIST ATTRIBUTES for a list of currently defined attributes.
-+
-Supported if the helper has the "fetch" or "import" capability.
-
-'list for-push'::
-       Similar to 'list', except that it is used if and only if
-       the caller wants to the resulting ref list to prepare
-       push commands.
-       A helper supporting both push and fetch can use this
-       to distinguish for which operation the output of 'list'
-       is going to be used, possibly reducing the amount
-       of work that needs to be performed.
-+
-Supported if the helper has the "push" or "export" capability.
-
-'option' <name> <value>::
-       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 valid
-       for it).  Options should be set before other commands,
-       and may influence the behavior of those commands.
-+
-See OPTIONS for a list of currently defined options.
-+
-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, 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 output of 'list' with a sha1 may be fetched this way.
-+
-Optionally may output a 'lock <file>' line indicating a file under
-GIT_DIR/objects/pack which is keeping a pack until refs can be
-suitably updated.
-+
-Supported if the helper has the "fetch" capability.
-
-'push' +<src>:<dst>::
-       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
-       (if there is only one reference to push, a single 'push' command
-       is followed by a blank line). For example, the following would
-       be two batches of 'push', the first asking the remote-helper
-       to push the local ref 'master' to the remote ref 'master' and
-       the local 'HEAD' to the remote 'branch', and the second
-       asking to push ref 'foo' to ref 'bar' (forced update requested
-       by the '+').
-+
-------------
-push refs/heads/master:refs/heads/master
-push HEAD:refs/heads/branch
-\n
-push +refs/heads/foo:refs/heads/bar
-\n
-------------
-+
-Zero or more protocol options may be entered after the last 'push'
-command, before the batch's terminating blank line.
-+
-When the push is complete, outputs one or more 'ok <dst>' or
-'error <dst> <why>?' lines to indicate success or failure of
-each pushed ref.  The status report output is terminated by
-a blank line.  The option field <why> may be quoted in a C
-style string if it contains an LF.
-+
-Supported if the helper has the "push" capability.
-
-'import' <name>::
-       Produces a fast-import stream which imports the current value
-       of the named ref. It may additionally import other refs as
-       needed to construct the history efficiently. The script writes
-       to a helper-specific private namespace. The value of the named
-       ref should be written to a location in this namespace derived
-       by applying the refspecs from the "refspec" capability to the
-       name of the ref.
-+
-Especially useful for interoperability with a foreign versioning
-system.
-+
-Just like 'push', a batch sequence of one or more 'import' is
-terminated with a blank line. For each batch of 'import', the remote
-helper should produce a fast-import stream terminated by a 'done'
-command.
-+
-Note that if the 'bidi-import' capability is used the complete batch
-sequence has to be buffered before starting to send data to fast-import
-to prevent mixing of commands and fast-import responses on the helper's
-stdin.
-+
-Supported if the helper has the "import" capability.
-
-'export'::
-       Instructs the remote helper that any subsequent input is
-       part of a fast-import stream (generated by 'git fast-export')
-       containing objects which should be pushed to the remote.
-+
-Especially useful for interoperability with a foreign versioning
-system.
-+
-The 'export-marks' and 'import-marks' capabilities, if specified,
-affect this command in so far as they are passed on to 'git
-fast-export', which then will load/store a table of marks for
-local objects. This can be used to implement for incremental
-operations.
-+
-Supported if the helper has the "export" capability.
-
-'connect' <service>::
-       Connects to given service. Standard input and standard output
-       of helper are connected to specified service (git prefix is
-       included in service name so e.g. fetching uses 'git-upload-pack'
-       as service) on remote side. Valid replies to this command are
-       empty line (connection established), 'fallback' (no smart
-       transport support, fall back to dumb transports) and just
-       exiting with error message printed (can't connect, don't
-       bother trying to fall back). After line feed terminating the
-       positive (empty) response, the output of service starts. After
-       the connection ends, the remote helper exits.
-+
-Supported if the helper has the "connect" capability.
-
-If a fatal error occurs, the program writes the error message to
-stderr and exits. The caller should expect that a suitable error
-message has been printed if the child closes the connection without
-completing a valid response for the current command.
-
-Additional commands may be supported, as may be determined from
-capabilities reported by the helper.
-
-REF LIST ATTRIBUTES
--------------------
-
-The 'list' command produces a list of refs in which each ref
-may be followed by a list of attributes. The following ref list
-attributes are defined.
-
-'unchanged'::
-       This ref is unchanged since the last import or fetch, although
-       the helper cannot necessarily determine what value that produced.
-
-OPTIONS
--------
-
-The following options are defined and (under suitable circumstances)
-set by git if the remote helper has the 'option' capability.
-
-'option verbosity' <n>::
-       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'\}::
-       Enables (or disables) progress messages displayed by the
-       transport helper during a command.
-
-'option depth' <depth>::
-       Deepens the history of a shallow repository.
-
-'option followtags' \{'true'|'false'\}::
-       If enabled the helper should automatically fetch annotated
-       tag objects if the object the tag points at was transferred
-       during the fetch command.  If the tag is not fetched by
-       the helper a second fetch command will usually be sent to
-       ask for the tag specifically.  Some helpers may be able to
-       use this option to avoid a second network connection.
-
-'option dry-run' \{'true'|'false'\}:
-       If true, pretend the operation completed successfully,
-       but don't actually change any repository data.  For most
-       helpers this only applies to the 'push', if supported.
-
-'option servpath <c-style-quoted-path>'::
-       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]
-
-linkgit:git-remote-testgit[1]
-
-GIT
----
-Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote-helpers.txto b/Documentation/git-remote-helpers.txto
new file mode 100644 (file)
index 0000000..49233f5
--- /dev/null
@@ -0,0 +1,9 @@
+git-remote-helpers
+==================
+
+This document has been moved to linkgit:gitremote-helpers[1].
+
+Please let the owners of the referring site know so that they can update the
+link you clicked to get here.
+
+Thanks.
index 2a67d456a3d2e278d924e792760dfd90f77a680c..4c871b92e99aeb838a0975502e56a7388cad4965 100644 (file)
@@ -23,7 +23,7 @@ The best way to learn more is to read the comments and source code in
 
 SEE ALSO
 --------
-linkgit:git-remote-helpers[1]
+linkgit:gitremote-helpers[1]
 
 GIT
 ---
index afeb4cdf16df91f63197d390fdbf1540eff66837..c308e91537a02817560d3108be5517d1806b0c9e 100644 (file)
@@ -56,6 +56,9 @@ OPTIONS
        line of each entry is indented by `indent1` spaces, and the second
        and subsequent lines are indented by `indent2` spaces. `width`,
        `indent1`, and `indent2` default to 76, 6 and 9 respectively.
++
+If width is `0` (zero) then indent the lines of the output without wrapping
+them.
 
 
 MAPPING AUTHORS
index 8b0d3adfede9ebffbddc294d6f30eedea0e2dfa0..69decb13b0ec672cd9ccc83a67a08f1725473324 100644 (file)
@@ -628,10 +628,19 @@ ADVANCED OPTIONS
        Default: "svn"
 
 --follow-parent::
+       This option is only relevant if we are tracking branches (using
+       one of the repository layout options --trunk, --tags,
+       --branches, --stdlayout). For each tracked branch, try to find
+       out where its revision was copied from, and set
+       a suitable parent in the first git commit for the branch.
        This is especially helpful when we're tracking a directory
-       that has been moved around within the repository, or if we
-       started tracking a branch and never tracked the trunk it was
-       descended from. This feature is enabled by default, use
+       that has been moved around within the repository.  If this
+       feature is disabled, the branches created by 'git svn' will all
+       be linear and not share any history, meaning that there will be
+       no information on where branches were branched off or merged.
+       However, following long/convoluted histories can take a long
+       time, so disabling this feature may speed up the cloning
+       process. This feature is enabled by default, use
        --no-follow-parent to disable it.
 +
 [verse]
@@ -739,7 +748,8 @@ for rewriteRoot and rewriteUUID which can be used together.
 BASIC EXAMPLES
 --------------
 
-Tracking and contributing to the trunk of a Subversion-managed project:
+Tracking and contributing to the trunk of a Subversion-managed project
+(ignoring tags and branches):
 
 ------------------------------------------------------------------------
 # Clone a repo (like git clone):
@@ -764,8 +774,10 @@ Tracking and contributing to an entire Subversion-managed project
 (complete with a trunk, tags and branches):
 
 ------------------------------------------------------------------------
-# Clone a repo (like git clone):
-       git svn clone http://svn.example.com/project -T trunk -b branches -t tags
+# Clone a repo with standard SVN directory layout (like git clone):
+       git svn clone http://svn.example.com/project --stdlayout
+# Or, if the repo uses a non-standard directory layout:
+       git svn clone http://svn.example.com/project -T tr -b branch -t tag
 # View all branches and tags you have cloned:
        git branch -r
 # Create a new branch in SVN
@@ -830,6 +842,52 @@ inside git back upstream to SVN users.  Therefore it is advised that
 users keep history as linear as possible inside git to ease
 compatibility with SVN (see the CAVEATS section below).
 
+HANDLING OF SVN BRANCHES
+------------------------
+If 'git svn' is configured to fetch branches (and --follow-branches
+is in effect), it sometimes creates multiple git branches for one
+SVN branch, where the addtional branches have names of the form
+'branchname@nnn' (with nnn an SVN revision number).  These additional
+branches are created if 'git svn' cannot find a parent commit for the
+first commit in an SVN branch, to connect the branch to the history of
+the other branches.
+
+Normally, the first commit in an SVN branch consists
+of a copy operation. 'git svn' will read this commit to get the SVN
+revision the branch was created from. It will then try to find the
+git commit that corresponds to this SVN revision, and use that as the
+parent of the branch. However, it is possible that there is no suitable
+git commit to serve as parent.  This will happen, among other reasons,
+if the SVN branch is a copy of a revision that was not fetched by 'git
+svn' (e.g. because it is an old revision that was skipped with
+'--revision'), or if in SVN a directory was copied that is not tracked
+by 'git svn' (such as a branch that is not tracked at all, or a
+subdirectory of a tracked branch). In these cases, 'git svn' will still
+create a git branch, but instead of using an existing git commit as the
+parent of the branch, it will read the SVN history of the directory the
+branch was copied from and create appropriate git commits.  This is
+indicated by the message "Initializing parent: <branchname>".
+
+Additionally, it will create a special branch named
+'<branchname>@<SVN-Revision>', where <SVN-Revision> is the SVN revision
+number the branch was copied from.  This branch will point to the newly
+created parent commit of the branch.  If in SVN the branch was deleted
+and later recreated from a different version, there will be multiple
+such branches with an '@'.
+
+Note that this may mean that multiple git commits are created for a
+single SVN revision.
+
+An example: in an SVN repository with a standard
+trunk/tags/branches layout, a directory trunk/sub is created in r.100.
+In r.200, trunk/sub is branched by copying it to branches/. 'git svn
+clone -s' will then create a branch 'sub'. It will also create new git
+commits for r.100 through r.199 and use these as the history of branch
+'sub'. Thus there will be two git commits for each revision from r.100
+to r.199 (one containing trunk/, one containing trunk/sub/). Finally,
+it will create a branch 'sub@200' pointing to the new parent commit of
+branch 'sub' (i.e. the commit for r.200 and trunk/sub/).
+
 CAVEATS
 -------
 
@@ -871,6 +929,21 @@ already dcommitted.  It is considered bad practice to --amend commits
 you've already pushed to a remote repository for other users, and
 dcommit with SVN is analogous to that.
 
+When cloning an SVN repository, if none of the options for describing
+the repository layout is used (--trunk, --tags, --branches,
+--stdlayout), 'git svn clone' will create a git repository with
+completely linear history, where branches and tags appear as separate
+directories in the working copy.  While this is the easiest way to get a
+copy of a complete repository, for projects with many branches it will
+lead to a working copy many times larger than just the trunk. Thus for
+projects using the standard directory structure (trunk/branches/tags),
+it is recommended to clone with option '--stdlayout'. If the project
+uses a non-standard structure, and/or if branches and tags are not
+required, it is easiest to only clone one directory (typically trunk),
+without giving any repository layout options.  If the full history with
+branches and tags is required, the options '--trunk' / '--branches' /
+'--tags' must be used.
+
 When using multiple --branches or --tags, 'git svn' does not automatically
 handle name collisions (for example, if two branches from different paths have
 the same name, or if a branch and a tag have the same name).  In these cases,
@@ -894,6 +967,12 @@ the possible corner cases (git doesn't do it, either).  Committing
 renamed and copied files is fully supported if they're similar enough
 for git to detect them.
 
+In SVN, it is possible (though discouraged) to commit changes to a tag
+(because a tag is just a directory copy, thus technically the same as a
+branch). When cloning an SVN repository, 'git svn' cannot know if such a
+commit to a tag will happen in the future. Thus it acts conservatively
+and imports all SVN tags as branches, prefixing the tag name with 'tags/'.
+
 CONFIGURATION
 -------------
 
index 247534e908d9f5b804a60b6707d1962eccc9bb1a..6470cffd325f919d8daa6ddb2ef70cf79334c30f 100644 (file)
@@ -129,7 +129,7 @@ This option is only applicable when listing tags without annotation lines.
 CONFIGURATION
 -------------
 By default, 'git tag' in sign-with-default mode (-s) will use your
-committer identity (of the form "Your Name <your@email.address>") to
+committer identity (of the form "Your Name <\your@email.address>") to
 find a key.  If you want to use a different default key, you can specify
 it in the repository configuration as follows:
 
index 1d797f27ed7682cf7308949b99d4bc27f9767f1a..da0115f3d0569c2a7addaf5eff49a06d0ebf572c 100644 (file)
@@ -43,9 +43,19 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.8.0.2/git.html[documentation for release 1.8.0.2]
+* link:v1.8.1.4/git.html[documentation for release 1.8.1.4]
 
 * release notes for
+  link:RelNotes/1.8.1.4.txt[1.8.1.4],
+  link:RelNotes/1.8.1.3.txt[1.8.1.3],
+  link:RelNotes/1.8.1.2.txt[1.8.1.2],
+  link:RelNotes/1.8.1.1.txt[1.8.1.1],
+  link:RelNotes/1.8.1.txt[1.8.1].
+
+* link:v1.8.0.3/git.html[documentation for release 1.8.0.3]
+
+* release notes for
+  link:RelNotes/1.8.0.3.txt[1.8.0.3],
   link:RelNotes/1.8.0.2.txt[1.8.0.2],
   link:RelNotes/1.8.0.1.txt[1.8.0.1],
   link:RelNotes/1.8.0.txt[1.8.0].
@@ -766,6 +776,14 @@ for further details.
        and read the password from its STDOUT. See also the 'core.askpass'
        option in linkgit:git-config[1].
 
+'GIT_CONFIG_NOSYSTEM'::
+       Whether to skip reading settings from the system-wide
+       `$(prefix)/etc/gitconfig` file.  This environment variable can
+       be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
+       predictable environment for a picky script, or you can set it
+       temporarily to avoid using a buggy `/etc/gitconfig` file while
+       waiting for someone with sufficient permissions to fix it.
+
 'GIT_FLUSH'::
        If this environment variable is set to "1", then commands such
        as 'git blame' (in incremental mode), 'git rev-list', 'git log',
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
new file mode 100644 (file)
index 0000000..0f21367
--- /dev/null
@@ -0,0 +1,423 @@
+gitremote-helpers(1)
+====================
+
+NAME
+----
+gitremote-helpers - Helper programs to interact with remote repositories
+
+SYNOPSIS
+--------
+[verse]
+'git remote-<transport>' <repository> [<URL>]
+
+DESCRIPTION
+-----------
+
+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
+uses to determine what other commands the helper will accept.  Those
+other commands can be used to discover and update remote refs,
+transport objects between the object database and the remote repository,
+and update the local object store.
+
+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.
+The 'GIT_DIR' environment variable is set up for the remote helper
+and can be used to determine where to store additional data or from
+which directory to invoke auxiliary git commands.
+
+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.
+
+INPUT FORMAT
+------------
+
+Git sends the remote helper a list of commands on standard input, one
+per line.  The first command is always the 'capabilities' command, in
+response to which the remote helper must print a list of the
+capabilities it supports (see below) followed by a blank line.  The
+response to the capabilities command determines what commands Git uses
+in the remainder of the command stream.
+
+The command stream is terminated by a blank line.  In some cases
+(indicated in the documentation of the relevant commands), this blank
+line is followed by a payload in some other protocol (e.g., the pack
+protocol), while in others it indicates the end of input.
+
+Capabilities
+~~~~~~~~~~~~
+
+Each remote helper is expected to support only a subset of commands.
+The operations a helper supports are declared to git in the response
+to the `capabilities` command (see COMMANDS, below).
+
+In the following, we list all defined capabilities and for
+each we list which commands a helper with that capability
+must provide.
+
+Capabilities for Pushing
+^^^^^^^^^^^^^^^^^^^^^^^^
+'connect'::
+       Can attempt to connect to 'git receive-pack' (for pushing),
+       'git upload-pack', etc for communication using
+       git's native packfile protocol. This
+       requires a bidirectional, full-duplex connection.
++
+Supported commands: 'connect'.
+
+'push'::
+       Can discover remote refs and push local commits and the
+       history leading up to them to new or existing remote refs.
++
+Supported commands: 'list for-push', 'push'.
+
+'export'::
+       Can discover remote refs and push specified objects from a
+       fast-import stream to remote refs.
++
+Supported commands: 'list for-push', 'export'.
+
+If a helper advertises 'connect', git will use it if possible and
+fall back to another capability if the helper requests so when
+connecting (see the 'connect' command under COMMANDS).
+When choosing between 'push' and 'export', git prefers 'push'.
+Other frontends may have some other order of preference.
+
+
+Capabilities for Fetching
+^^^^^^^^^^^^^^^^^^^^^^^^^
+'connect'::
+       Can try to connect to 'git upload-pack' (for fetching),
+       'git receive-pack', etc for communication using the
+       git's native packfile protocol. This
+       requires a bidirectional, full-duplex connection.
++
+Supported commands: 'connect'.
+
+'fetch'::
+       Can discover remote refs and transfer objects reachable from
+       them to the local object store.
++
+Supported commands: 'list', 'fetch'.
+
+'import'::
+       Can discover remote refs and output objects reachable from
+       them as a stream in fast-import format.
++
+Supported commands: 'list', 'import'.
+
+If a helper advertises 'connect', git will use it if possible and
+fall back to another capability if the helper requests so when
+connecting (see the 'connect' command under COMMANDS).
+When choosing between 'fetch' and 'import', git prefers 'fetch'.
+Other frontends may have some other order of preference.
+
+Miscellaneous capabilities
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+'option'::
+       For specifying settings like `verbosity` (how much output to
+       write to stderr) and `depth` (how much history is wanted in the
+       case of a shallow clone) that affect how other commands are
+       carried out.
+
+'refspec' <refspec>::
+       This modifies the 'import' capability, allowing the produced
+       fast-import stream to modify refs in a private namespace
+       instead of writing to refs/heads or refs/remotes directly.
+       It is recommended that all importers providing the 'import'
+       capability use this.
++
+A helper advertising the capability
+`refspec refs/heads/*:refs/svn/origin/branches/*`
+is saying that, when it is asked to `import refs/heads/topic`, the
+stream it outputs will update the `refs/svn/origin/branches/topic`
+ref.
++
+This capability can be advertised multiple times.  The first
+applicable refspec takes precedence.  The left-hand of refspecs
+advertised with this capability must cover all refs reported by
+the list command.  If no 'refspec' capability is advertised,
+there is an implied `refspec *:*`.
+
+'bidi-import'::
+       This modifies the 'import' capability.
+       The fast-import commands 'cat-blob' and 'ls' can be used by remote-helpers
+       to retrieve information about blobs and trees that already exist in
+       fast-import's memory. This requires a channel from fast-import to the
+       remote-helper.
+       If it is advertised in addition to "import", git establishes a pipe from
+       fast-import to the remote-helper's stdin.
+       It follows that git and fast-import are both connected to the
+       remote-helper's stdin. Because git can send multiple commands to
+       the remote-helper it is required that helpers that use 'bidi-import'
+       buffer all 'import' commands of a batch before sending data to fast-import.
+       This is to prevent mixing commands and fast-import responses on the
+       helper's stdin.
+
+'export-marks' <file>::
+       This modifies the 'export' capability, instructing git to dump the
+       internal marks table to <file> when complete. For details,
+       read up on '--export-marks=<file>' in linkgit:git-fast-export[1].
+
+'import-marks' <file>::
+       This modifies the 'export' capability, instructing git to load the
+       marks specified in <file> before processing any input. For details,
+       read up on '--import-marks=<file>' in linkgit:git-fast-export[1].
+
+
+
+
+COMMANDS
+--------
+
+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 '*',
+       which marks them mandatory for git versions using the remote
+       helper to understand. Any unknown mandatory capability is a
+       fatal error.
++
+Support for this command is mandatory.
+
+'list'::
+       Lists the refs, one per line, in the format "<value> <name>
+       [<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. The list ends
+       with a blank line.
++
+See REF LIST ATTRIBUTES for a list of currently defined attributes.
++
+Supported if the helper has the "fetch" or "import" capability.
+
+'list for-push'::
+       Similar to 'list', except that it is used if and only if
+       the caller wants to the resulting ref list to prepare
+       push commands.
+       A helper supporting both push and fetch can use this
+       to distinguish for which operation the output of 'list'
+       is going to be used, possibly reducing the amount
+       of work that needs to be performed.
++
+Supported if the helper has the "push" or "export" capability.
+
+'option' <name> <value>::
+       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 valid
+       for it).  Options should be set before other commands,
+       and may influence the behavior of those commands.
++
+See OPTIONS for a list of currently defined options.
++
+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, 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 output of 'list' with a sha1 may be fetched this way.
++
+Optionally may output a 'lock <file>' line indicating a file under
+GIT_DIR/objects/pack which is keeping a pack until refs can be
+suitably updated.
++
+Supported if the helper has the "fetch" capability.
+
+'push' +<src>:<dst>::
+       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
+       (if there is only one reference to push, a single 'push' command
+       is followed by a blank line). For example, the following would
+       be two batches of 'push', the first asking the remote-helper
+       to push the local ref 'master' to the remote ref 'master' and
+       the local 'HEAD' to the remote 'branch', and the second
+       asking to push ref 'foo' to ref 'bar' (forced update requested
+       by the '+').
++
+------------
+push refs/heads/master:refs/heads/master
+push HEAD:refs/heads/branch
+\n
+push +refs/heads/foo:refs/heads/bar
+\n
+------------
++
+Zero or more protocol options may be entered after the last 'push'
+command, before the batch's terminating blank line.
++
+When the push is complete, outputs one or more 'ok <dst>' or
+'error <dst> <why>?' lines to indicate success or failure of
+each pushed ref.  The status report output is terminated by
+a blank line.  The option field <why> may be quoted in a C
+style string if it contains an LF.
++
+Supported if the helper has the "push" capability.
+
+'import' <name>::
+       Produces a fast-import stream which imports the current value
+       of the named ref. It may additionally import other refs as
+       needed to construct the history efficiently. The script writes
+       to a helper-specific private namespace. The value of the named
+       ref should be written to a location in this namespace derived
+       by applying the refspecs from the "refspec" capability to the
+       name of the ref.
++
+Especially useful for interoperability with a foreign versioning
+system.
++
+Just like 'push', a batch sequence of one or more 'import' is
+terminated with a blank line. For each batch of 'import', the remote
+helper should produce a fast-import stream terminated by a 'done'
+command.
++
+Note that if the 'bidi-import' capability is used the complete batch
+sequence has to be buffered before starting to send data to fast-import
+to prevent mixing of commands and fast-import responses on the helper's
+stdin.
++
+Supported if the helper has the "import" capability.
+
+'export'::
+       Instructs the remote helper that any subsequent input is
+       part of a fast-import stream (generated by 'git fast-export')
+       containing objects which should be pushed to the remote.
++
+Especially useful for interoperability with a foreign versioning
+system.
++
+The 'export-marks' and 'import-marks' capabilities, if specified,
+affect this command in so far as they are passed on to 'git
+fast-export', which then will load/store a table of marks for
+local objects. This can be used to implement for incremental
+operations.
++
+Supported if the helper has the "export" capability.
+
+'connect' <service>::
+       Connects to given service. Standard input and standard output
+       of helper are connected to specified service (git prefix is
+       included in service name so e.g. fetching uses 'git-upload-pack'
+       as service) on remote side. Valid replies to this command are
+       empty line (connection established), 'fallback' (no smart
+       transport support, fall back to dumb transports) and just
+       exiting with error message printed (can't connect, don't
+       bother trying to fall back). After line feed terminating the
+       positive (empty) response, the output of service starts. After
+       the connection ends, the remote helper exits.
++
+Supported if the helper has the "connect" capability.
+
+If a fatal error occurs, the program writes the error message to
+stderr and exits. The caller should expect that a suitable error
+message has been printed if the child closes the connection without
+completing a valid response for the current command.
+
+Additional commands may be supported, as may be determined from
+capabilities reported by the helper.
+
+REF LIST ATTRIBUTES
+-------------------
+
+The 'list' command produces a list of refs in which each ref
+may be followed by a list of attributes. The following ref list
+attributes are defined.
+
+'unchanged'::
+       This ref is unchanged since the last import or fetch, although
+       the helper cannot necessarily determine what value that produced.
+
+OPTIONS
+-------
+
+The following options are defined and (under suitable circumstances)
+set by git if the remote helper has the 'option' capability.
+
+'option verbosity' <n>::
+       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'\}::
+       Enables (or disables) progress messages displayed by the
+       transport helper during a command.
+
+'option depth' <depth>::
+       Deepens the history of a shallow repository.
+
+'option followtags' \{'true'|'false'\}::
+       If enabled the helper should automatically fetch annotated
+       tag objects if the object the tag points at was transferred
+       during the fetch command.  If the tag is not fetched by
+       the helper a second fetch command will usually be sent to
+       ask for the tag specifically.  Some helpers may be able to
+       use this option to avoid a second network connection.
+
+'option dry-run' \{'true'|'false'\}:
+       If true, pretend the operation completed successfully,
+       but don't actually change any repository data.  For most
+       helpers this only applies to the 'push', if supported.
+
+'option servpath <c-style-quoted-path>'::
+       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]
+
+linkgit:git-remote-testgit[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
index ea6e4a52c91ced6a86f85408971ee16686ba8baa..816c791502f99cdb2f2ca996e30d1b73cb95a6ac 100644 (file)
@@ -10,35 +10,42 @@ Content-type: text/asciidoc
 How to maintain Git
 ===================
 
+Activities
+----------
+
 The maintainer's git time is spent on three activities.
 
- - Communication (60%)
+ - Communication (45%)
 
    Mailing list discussions on general design, fielding user
    questions, diagnosing bug reports; reviewing, commenting on,
    suggesting alternatives to, and rejecting patches.
 
- - Integration (30%)
+ - Integration (50%)
 
    Applying new patches from the contributors while spotting and
    correcting minor mistakes, shuffling the integration and
    testing branches, pushing the results out, cutting the
    releases, and making announcements.
 
- - Own development (10%)
+ - Own development (5%)
 
    Scratching my own itch and sending proposed patch series out.
 
+The Policy
+----------
+
 The policy on Integration is informally mentioned in "A Note
 from the maintainer" message, which is periodically posted to
 this mailing list after each feature release is made.
 
-The policy.
-
  - Feature releases are numbered as vX.Y.Z and are meant to
    contain bugfixes and enhancements in any area, including
    functionality, performance and usability, without regression.
 
+ - One release cycle for a feature release is expected to last for
+   eight to ten weeks.
+
  - Maintenance releases are numbered as vX.Y.Z.W and are meant
    to contain only bugfixes for the corresponding vX.Y.Z feature
    release and earlier maintenance releases vX.Y.Z.V (V < W).
@@ -62,12 +69,15 @@ The policy.
  - 'pu' branch is used to publish other proposed changes that do
    not yet pass the criteria set for 'next'.
 
- - The tips of 'master', 'maint' and 'next' branches will always
-   fast-forward, to allow people to build their own
-   customization on top of them.
+ - The tips of 'master' and 'maint' branches will not be rewound to
+   allow people to build their own customization on top of them.
+   Early in a new development cycle, 'next' is rewound to the tip of
+   'master' once, but otherwise it will not be rewound until the end
+   of the cycle.
 
- - Usually 'master' contains all of 'maint', 'next' contains all
-   of 'master' and 'pu' contains all of 'next'.
+ - Usually 'master' contains all of 'maint' and 'next' contains all
+   of 'master'.  'pu' contains all the topics merged to 'next', but
+   is rebuilt directly on 'master'.
 
  - The tip of 'master' is meant to be more stable than any
    tagged releases, and the users are encouraged to follow it.
@@ -77,14 +87,22 @@ The policy.
    are found before new topics are merged to 'master'.
 
 
+A Typical Git Day
+-----------------
+
 A typical git day for the maintainer implements the above policy
 by doing the following:
 
- - Scan mailing list and #git channel log.  Respond with review
-   comments, suggestions etc.  Kibitz.  Collect potentially
-   usable patches from the mailing list.  Patches about a single
-   topic go to one mailbox (I read my mail in Gnus, and type
-   \C-o to save/append messages in files in mbox format).
+ - Scan mailing list.  Respond with review comments, suggestions
+   etc.  Kibitz.  Collect potentially usable patches from the
+   mailing list.  Patches about a single topic go to one mailbox (I
+   read my mail in Gnus, and type \C-o to save/append messages in
+   files in mbox format).
+
+ - Write his own patches to address issues raised on the list but
+   nobody has stepped up solving.  Send it out just like other
+   contributors do, and pick them up just like patches from other
+   contributors (see above).
 
  - Review the patches in the saved mailboxes.  Edit proposed log
    message for typofixes and clarifications, and add Acks
@@ -100,40 +118,32 @@ by doing the following:
    - Obviously correct fixes that pertain to the tip of 'master'
      are directly applied to 'master'.
 
+   - Other topics are not handled in this step.
+
    This step is done with "git am".
 
      $ git checkout master    ;# or "git checkout maint"
-     $ git am -3 -s mailbox
+     $ git am -sc3 mailbox
      $ make test
 
- - Merge downwards (maint->master):
-
-     $ git checkout master
-     $ git merge maint
-     $ make test
+   In practice, almost no patch directly goes to 'master' or
+   'maint'.
 
  - Review the last issue of "What's cooking" message, review the
-   topics scheduled for merging upwards (topic->master and
-   topic->maint), and merge.
+   topics ready for merging (topic->master and topic->maint).  Use
+   "Meta/cook -w" script (where Meta/ contains a checkout of the
+   'todo' branch) to aid this step.
+
+   And perform the merge.  Use "Meta/Reintegrate -e" script (see
+   later) to aid this step.
+
+     $ Meta/cook -w last-issue-of-whats-cooking.mbox
 
      $ git checkout master    ;# or "git checkout maint"
-     $ git merge ai/topic     ;# or "git merge ai/maint-topic"
+     $ echo ai/topic | Meta/Reintegrate -e ;# "git merge ai/topic"
      $ git log -p ORIG_HEAD.. ;# final review
      $ git diff ORIG_HEAD..   ;# final review
      $ make test              ;# final review
-     $ git branch -d ai/topic ;# or "git branch -d ai/maint-topic"
-
- - Merge downwards (maint->master) if needed:
-
-     $ git checkout master
-     $ git merge maint
-     $ make test
-
- - Merge downwards (master->next) if needed:
-
-     $ git checkout next
-     $ git merge master
-     $ make test
 
  - Handle the remaining patches:
 
@@ -142,9 +152,9 @@ by doing the following:
      and not in 'master') is applied to a new topic branch that
      is forked from the tip of 'master'.  This includes both
      enhancements and unobvious fixes to 'master'.  A topic
-     branch is named as ai/topic where "ai" is typically
-     author's initial and "topic" is a descriptive name of the
-     topic (in other words, "what's the series is about").
+     branch is named as ai/topic where "ai" is two-letter string
+     named after author's initial and "topic" is a descriptive name
+     of the topic (in other words, "what's the series is about").
 
    - An unobvious fix meant for 'maint' is applied to a new
      topic branch that is forked from the tip of 'maint'.  The
@@ -162,7 +172,8 @@ by doing the following:
 
    The above except the "replacement" are all done with:
 
-     $ git am -3 -s mailbox
+     $ git checkout ai/topic ;# or "git checkout -b ai/topic master"
+     $ git am -sc3 mailbox
 
    while patch replacement is often done by:
 
@@ -170,93 +181,170 @@ by doing the following:
 
    then replace some parts with the new patch, and reapplying:
 
+     $ git checkout ai/topic
      $ git reset --hard ai/topic~$n
-     $ git am -3 -s 000*.txt
+     $ git am -sc3 -s 000*.txt
 
    The full test suite is always run for 'maint' and 'master'
    after patch application; for topic branches the tests are run
    as time permits.
 
- - Update "What's cooking" message to review the updates to
-   existing topics, newly added topics and graduated topics.
+ - Merge maint to master as needed:
 
-   This step is helped with Meta/cook script (where Meta/ contains
-   a checkout of the 'todo' branch).
-
- - Merge topics to 'next'.  For each branch whose tip is not
-   merged to 'next', one of three things can happen:
+     $ git checkout master
+     $ git merge maint
+     $ make test
 
  - The commits are all next-worthy; merge the topic to next:
- Merge master to next as needed:
 
      $ git checkout next
-     $ git merge ai/topic     ;# or "git merge ai/maint-topic"
+     $ git merge master
      $ make test
 
+ - Review the last issue of "What's cooking" again and see if topics
+   that are ready to be merged to 'next' are still in good shape
+   (e.g. has there any new issue identified on the list with the
+   series?)
+
+ - Prepare 'jch' branch, which is used to represent somewhere
+   between 'master' and 'pu' and often is slightly ahead of 'next'.
+
+     $ Meta/Reintegrate master..pu >Meta/redo-jch.sh
+
+   The result is a script that lists topics to be merged in order to
+   rebuild 'pu' as the input to Meta/Reintegrate script.  Remove
+   later topics that should not be in 'jch' yet.  Add a line that
+   consists of '### match next' before the name of the first topic
+   in the output that should be in 'jch' but not in 'next' yet.
+
+ - Now we are ready to start merging topics to 'next'.  For each
+   branch whose tip is not merged to 'next', one of three things can
+   happen:
+
+   - The commits are all next-worthy; merge the topic to next;
    - The new parts are of mixed quality, but earlier ones are
-     next-worthy; merge the early parts to next:
+     next-worthy; merge the early parts to next;
+   - Nothing is next-worthy; do not do anything.
+
+   This step is aided with Meta/redo-jch.sh script created earlier.
+   If a topic that was already in 'next' gained a patch, the script
+   would list it as "ai/topic~1".  To include the new patch to the
+   updated 'next', drop the "~1" part; to keep it excluded, do not
+   touch the line.  If a topic that was not in 'next' should be
+   merged to 'next', add it at the end of the list.  Then:
+
+     $ git checkout -B jch master
+     $ Meta/redo-jch.sh -c1
+
+   to rebuild the 'jch' branch from scratch.  "-c1" tells the script
+   to stop merging at the first line that begins with '###'
+   (i.e. the "### match next" line you added earlier).
+
+   At this point, build-test the result.  It may reveal semantic
+   conflicts (e.g. a topic renamed a variable, another added a new
+   reference to the variable under its old name), in which case
+   prepare an appropriate merge-fix first (see appendix), and
+   rebuild the 'jch' branch from scratch, starting at the tip of
+   'master'.
+
+   Then do the same to 'next'
 
      $ git checkout next
-     $ git merge ai/topic~2   ;# the tip two are dubious
-     $ make test
+     $ sh Meta/redo-jch.sh -c1 -e
 
-   - Nothing is next-worthy; do not do anything.
+   The "-e" option allows the merge message that comes from the
+   history of the topic and the comments in the "What's cooking" to
+   be edited.  The resulting tree should match 'jch' as the same set
+   of topics are merged on 'master'; otherwise there is a mismerge.
+   Investigate why and do not proceed until the mismerge is found
+   and rectified.
 
- - [** OBSOLETE **] Optionally rebase topics that do not have any commit
-   in next yet, when they can take advantage of low-level framework
-   change that is merged to 'master' already.
+     $ git diff jch next
 
-     $ git rebase master ai/topic
+   When all is well, clean up the redo-jch.sh script with
 
-   This step is helped with Meta/git-topic.perl script to
-   identify which topic is rebaseable.  There also is a
-   pre-rebase hook to make sure that topics that are already in
-   'next' are not rebased beyond the merged commit.
+     $ sh Meta/redo-jch.sh -u
 
- - [** OBSOLETE **] Rebuild "pu" to merge the tips of topics not in 'next'.
+   This removes topics listed in the script that have already been
+   merged to 'master'.  This may lose '### match next' marker;
+   add it again to the appropriate place when it happens.
 
-     $ git checkout pu
-     $ git reset --hard next
-     $ git merge ai/topic     ;# repeat for all remaining topics
-     $ make test
+ - Rebuild 'pu'.
 
-   This step is helped with Meta/PU script
+     $ Meta/Reintegrate master..pu >Meta/redo-pu.sh
 
- - Push four integration branches to a private repository at
-   k.org and run "make test" on all of them.
+   Edit the result by adding new topics that are not still in 'pu'
+   in the script.  Then
 
- - Push four integration branches to /pub/scm/git/git.git at
-   k.org.  This triggers its post-update hook which:
+     $ git checkout -B pu jch
+     $ sh Meta/redo-pu.sh
 
-    (1) runs "git pull" in $HOME/git-doc/ repository to pull
-        'master' just pushed out;
+   When all is well, clean up the redo-pu.sh script with
 
-    (2) runs "make doc" in $HOME/git-doc/, install the generated
-        documentation in staging areas, which are separate
-        repositories that have html and man branches checked
-        out.
+     $ sh Meta/redo-pu.sh -u
 
-    (3) runs "git commit" in the staging areas, and run "git
-        push" back to /pub/scm/git/git.git/ to update the html
-        and man branches.
+   Double check by running
 
-    (4) installs generated documentation to /pub/software/scm/git/docs/
-        to be viewed from http://www.kernel.org/
+     $ git branch --no-merged pu
 
- - Fetch html and man branches back from k.org, and push four
-   integration branches and the two documentation branches to
-   repo.or.cz and other mirrors.
+   to see there is no unexpected leftover topics.
 
+   At this point, build-test the result for semantic conflicts, and
+   if there are, prepare an appropriate merge-fix first (see
+   appendix), and rebuild the 'pu' branch from scratch, starting at
+   the tip of 'jch'.
+
+ - Update "What's cooking" message to review the updates to
+   existing topics, newly added topics and graduated topics.
+
+   This step is helped with Meta/cook script.
+
+     $ Meta/cook
+
+   This script inspects the history between master..pu, finds tips
+   of topic branches, compares what it found with the current
+   contents in Meta/whats-cooking.txt, and updates that file.
+   Topics not listed in the file but are found in master..pu are
+   added to the "New topics" section, topics listed in the file that
+   are no longer found in master..pu are moved to the "Graduated to
+   master" section, and topics whose commits changed their states
+   (e.g. used to be only in 'pu', now merged to 'next') are updated
+   with change markers "<<" and ">>".
+
+   Look for lines enclosed in "<<" and ">>"; they hold contents from
+   old file that are replaced by this integration round.  After
+   verifying them, remove the old part.  Review the description for
+   each topic and update its doneness and plan as needed.  To review
+   the updated plan, run
+
+     $ Meta/cook -w
+
+   which will pick up comments given to the topics, such as "Will
+   merge to 'next'", etc. (see Meta/cook script to learn what kind
+   of phrases are supported).
+
+ - Compile, test and install all four (five) integration branches;
+   Meta/Dothem script may aid this step.
+
+ - Format documentation if the 'master' branch was updated;
+   Meta/dodoc.sh script may aid this step.
+
+ - Push the integration branches out to public places; Meta/pushall
+   script may aid this step.
+
+Observations
+------------
 
 Some observations to be made.
 
- * Each topic is tested individually, and also together with
-   other topics cooking in 'next'.  Until it matures, none part
-   of it is merged to 'master'.
+ * Each topic is tested individually, and also together with other
+   topics cooking first in 'pu', then in 'jch' and then in 'next'.
+   Until it matures, no part of it is merged to 'master'.
 
  * A topic already in 'next' can get fixes while still in
    'next'.  Such a topic will have many merges to 'next' (in
    other words, "git log --first-parent next" will show many
-   "Merge ai/topic to next" for the same topic.
+   "Merge branch 'ai/topic' to next" for the same topic.
 
  * An unobvious fix for 'maint' is cooked in 'next' and then
    merged to 'master' to make extra sure it is Ok and then
@@ -278,3 +366,80 @@ Some observations to be made.
  * Being in the 'next' branch is not a guarantee for a topic to
    be included in the next feature release.  Being in the
    'master' branch typically is.
+
+
+Appendix
+--------
+
+Preparing a "merge-fix"
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A merge of two topics may not textually conflict but still have
+conflict at the semantic level. A classic example is for one topic
+to rename an variable and all its uses, while another topic adds a
+new use of the variable under its old name. When these two topics
+are merged together, the reference to the variable newly added by
+the latter topic will still use the old name in the result.
+
+The Meta/Reintegrate script that is used by redo-jch and redo-pu
+scripts implements a crude but usable way to work this issue around.
+When the script merges branch $X, it checks if "refs/merge-fix/$X"
+exists, and if so, the effect of it is squashed into the result of
+the mechanical merge.  In other words,
+
+     $ echo $X | Meta/Reintegrate
+
+is roughly equivalent to this sequence:
+
+     $ git merge --rerere-autoupdate $X
+     $ git commit
+     $ git cherry-pick -n refs/merge-fix/$X
+     $ git commit --amend
+
+The goal of this "prepare a merge-fix" step is to come up with a
+commit that can be squashed into a result of mechanical merge to
+correct semantic conflicts.
+
+After finding that the result of merging branch "ai/topic" to an
+integration branch had such a semantic conflict, say pu~4, check the
+problematic merge out on a detached HEAD, edit the working tree to
+fix the semantic conflict, and make a separate commit to record the
+fix-up:
+
+     $ git checkout pu~4
+     $ git show -s --pretty=%s ;# double check
+     Merge branch 'ai/topic' to pu
+     $ edit
+     $ git commit -m 'merge-fix/ai/topic' -a
+
+Then make a reference "refs/merge-fix/ai/topic" to point at this
+result:
+
+     $ git update-ref refs/merge-fix/ai/topic HEAD
+
+Then double check the result by asking Meta/Reintegrate to redo the
+merge:
+
+     $ git checkout pu~5 ;# the parent of the problem merge
+     $ echo ai/topic | Meta/Reintegrate
+     $ git diff pu~4
+
+This time, because you prepared refs/merge-fix/ai/topic, the
+resulting merge should have been tweaked to include the fix for the
+semantic conflict.
+
+Note that this assumes that the order in which conflicting branches
+are merged does not change.  If the reason why merging ai/topic
+branch needs this merge-fix is because another branch merged earlier
+to the integration branch changed the underlying assumption ai/topic
+branch made (e.g. ai/topic branch added a site to refer to a
+variable, while the other branch renamed that variable and adjusted
+existing use sites), and if you changed redo-jch (or redo-pu) script
+to merge ai/topic branch before the other branch, then the above
+merge-fix should not be applied while merging ai/topic, but should
+instead be applied while merging the other branch.  You would need
+to move the fix to apply to the other branch, perhaps like this:
+
+      $ mf=refs/merge-fix
+      $ git update-ref $mf/$the_other_branch $mf/ai/topic
+      $ git update-ref -d $mf/ai/topic
diff --git a/Documentation/howto/new-command.txt b/Documentation/howto/new-command.txt
new file mode 100644 (file)
index 0000000..36502f6
--- /dev/null
@@ -0,0 +1,104 @@
+From: Eric S. Raymond <esr@thyrsus.com>
+Abstract: This is how-to documentation for people who want to add extension
+ commands to git.  It should be read alongside api-builtin.txt.
+Content-type: text/asciidoc
+
+How to integrate new subcommands
+================================
+
+This is how-to documentation for people who want to add extension
+commands to git.  It should be read alongside api-builtin.txt.
+
+Runtime environment
+-------------------
+
+git subcommands are standalone executables that live in the git exec
+path, normally /usr/lib/git-core.  The git executable itself is a
+thin wrapper that knows where the subcommands live, and runs them by
+passing command-line arguments to them.
+
+(If "git foo" is not found in the git exec path, the wrapper
+will look in the rest of your $PATH for it.  Thus, it's possible
+to write local git extensions that don't live in system space.)
+
+Implementation languages
+------------------------
+
+Most subcommands are written in C or shell.  A few are written in
+Perl.
+
+While we strongly encourage coding in portable C for portability,
+these specific scripting languages are also acceptable.  We won't
+accept more without a very strong technical case, as we don't want
+to broaden the git suite's required dependencies.  Import utilities,
+surgical tools, remote helpers and other code at the edges of the
+git suite are more lenient and we allow Python (and even Tcl/tk),
+but they should not be used for core functions.
+
+This may change in the future.  Especially Python is not allowed in
+core because we need better Python integration in the git Windows
+installer before we can be confident people in that environment
+won't experience an unacceptably large loss of capability.
+
+C commands are normally written as single modules, named after the
+command, that link a collection of functions called libgit.  Thus,
+your command 'git-foo' would normally be implemented as a single
+"git-foo.c" (or "builtin/foo.c" if it is to be linked to the main
+binary); this organization makes it easy for people reading the code
+to find things.
+
+See the CodingGuidelines document for other guidance on what we consider
+good practice in C and shell, and api-builtin.txt for the support
+functions available to built-in commands written in C.
+
+What every extension command needs
+----------------------------------
+
+You must have a man page, written in asciidoc (this is what git help
+followed by your subcommand name will display).  Be aware that there is
+a local asciidoc configuration and macros which you should use.  It's
+often helpful to start by cloning an existing page and replacing the
+text content.
+
+You must have a test, written to report in TAP (Test Anything Protocol).
+Tests are executables (usually shell scripts) that live in the 't'
+subdirectory of the tree.  Each test name begins with 't' and a sequence
+number that controls where in the test sequence it will be executed;
+conventionally the rest of the name stem is that of the command
+being tested.
+
+Read the file t/README to learn more about the conventions to be used
+in writing tests, and the test support library.
+
+Integrating a command
+---------------------
+
+Here are the things you need to do when you want to merge a new
+subcommand into the git tree.
+
+1. Don't forget to sign off your patch!
+
+2. Append your command name to one of the variables BUILTIN_OBJS,
+EXTRA_PROGRAMS, SCRIPT_SH, SCRIPT_PERL or SCRIPT_PYTHON.
+
+3. Drop its test in the t directory.
+
+4. If your command is implemented in an interpreted language with a
+p-code intermediate form, make sure .gitignore in the main directory
+includes a pattern entry that ignores such files.  Python .pyc and
+.pyo files will already be covered.
+
+5. If your command has any dependency on a particular version of
+your language, document it in the INSTALL file.
+
+6. There is a file command-list.txt in the distribution main directory
+that categorizes commands by type, so they can be listed in appropriate
+subsections in the documentation's summary command list.  Add an entry
+for yours.  To understand the categories, look at git-cmmands.txt
+in the main directory.
+
+7. Give the maintainer one paragraph to include in the RelNotes file
+to describe the new feature; a good place to do so is in the cover
+letter [PATCH 0/n].
+
+That's all there is to it.
index 288f04e70c8ea5f0b93a4b099a4a49d1fee13b79..dd89fca3f8996e119ce9d0cec0a6d9fc6616525d 100644 (file)
@@ -46,7 +46,7 @@ Jane Doe         <jane@desktop.(none)>
 Joe R. Developer <joe@example.com>
 ------------
 
-Note how there is no need for an entry for <jane@laptop.(none)>, because the
+Note how there is no need for an entry for `<jane@laptop.(none)>`, because the
 real name of that author is already correct.
 
 Example 2: Your repository contains commits from the following
diff --git a/Documentation/pt_BR/gittutorial.txt b/Documentation/pt_BR/gittutorial.txt
deleted file mode 100644 (file)
index beba065..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-gittutorial(7)
-==============
-
-NOME
-----
-gittutorial - Um tutorial de introdução ao git (para versão 1.5.1 ou mais nova)
-
-SINOPSE
---------
-git *
-
-DESCRIÇÃO
------------
-
-Este tutorial explica como importar um novo projeto para o git,
-adicionar mudanças a ele, e compartilhar mudanças com outros
-desenvolvedores.
-
-Se, ao invés disso, você está interessado primariamente em usar git para
-obter um projeto, por exemplo, para testar a Ãºltima versão, você pode
-preferir começar com os primeiros dois capítulos de
-link:user-manual.html[O Manual do Usuário Git].
-
-Primeiro, note que você pode obter documentação para um comando como
-`git log --graph` com:
-
-------------------------------------------------
-$ man git-log
-------------------------------------------------
-
-ou:
-
-------------------------------------------------
-$ git help log
-------------------------------------------------
-
-Com a Ãºltima forma, você pode usar o visualizador de manual de sua
-escolha; veja linkgit:git-help[1] para maior informação.
-
-É uma boa idéia informar ao git seu nome e endereço público de email
-antes de fazer qualquer operação. A maneira mais fácil de fazê-lo Ã©:
-
-------------------------------------------------
-$ git config --global user.name "Seu Nome Vem Aqui"
-$ git config --global user.email voce@seudominio.exemplo.com
-------------------------------------------------
-
-
-Importando um novo projeto
------------------------
-
-Assuma que você tem um tarball project.tar.gz com seu trabalho inicial.
-Você pode colocá-lo sob controle de revisão git da seguinte forma:
-
-------------------------------------------------
-$ tar xzf project.tar.gz
-$ cd project
-$ git init
-------------------------------------------------
-
-Git irá responder
-
-------------------------------------------------
-Initialized empty Git repository in .git/
-------------------------------------------------
-
-Agora que você iniciou seu diretório de trabalho, você deve ter notado que um
-novo diretório foi criado com o nome de ".git".
-
-A seguir, diga ao git para gravar um instantâneo do conteúdo de todos os
-arquivos sob o diretório atual (note o '.'), com 'git-add':
-
-------------------------------------------------
-$ git add .
-------------------------------------------------
-
-Este instantâneo está agora armazenado em uma Ã¡rea temporária que o git
-chama de "index" ou Ã­ndice. Você pode armazenar permanentemente o
-conteúdo do Ã­ndice no repositório com 'git-commit':
-
-------------------------------------------------
-$ git commit
-------------------------------------------------
-
-Isto vai te pedir por uma mensagem de commit. Você agora gravou sua
-primeira versão de seu projeto no git.
-
-Fazendo mudanças
---------------
-
-Modifique alguns arquivos, e, então, adicione seu conteúdo atualizado ao
-índice:
-
-------------------------------------------------
-$ git add file1 file2 file3
-------------------------------------------------
-
-Você está agora pronto para fazer o commit. Você pode ver o que está
-para ser gravado usando 'git-diff' com a opção --cached:
-
-------------------------------------------------
-$ git diff --cached
-------------------------------------------------
-
-(Sem --cached, o comando 'git-diff' irá te mostrar quaisquer mudanças
-que você tenha feito mas ainda não adicionou ao Ã­ndice.) Você também
-pode obter um breve sumário da situação com 'git-status':
-
-------------------------------------------------
-$ git status
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   file1
-#      modified:   file2
-#      modified:   file3
-#
-------------------------------------------------
-
-Se você precisar fazer qualquer outro ajuste, faça-o agora, e, então,
-adicione qualquer conteúdo modificado ao Ã­ndice. Finalmente, grave suas
-mudanças com:
-
-------------------------------------------------
-$ git commit
-------------------------------------------------
-
-Ao executar esse comando, ele irá te pedir uma mensagem descrevendo a mudança,
-e, então, irá gravar a nova versão do projeto.
-
-Alternativamente, ao invés de executar 'git-add' antes, você pode usar
-
-------------------------------------------------
-$ git commit -a
-------------------------------------------------
-
-o que irá automaticamente notar quaisquer arquivos modificados (mas não
-novos), adicioná-los ao Ã­ndices, e gravar, tudo em um Ãºnico passo.
-
-Uma nota em mensagens de commit: Apesar de não ser exigido, Ã© uma boa
-idéia começar a mensagem com uma simples e curta (menos de 50
-caracteres) linha sumarizando a mudança, seguida de uma linha em branco
-e, então, uma descrição mais detalhada. Ferramentas que transformam
-commits em email, por exemplo, usam a primeira linha no campo de
-cabeçalho "Subject:" e o resto no corpo.
-
-Git rastreia conteúdo, não arquivos
-----------------------------
-
-Muitos sistemas de controle de revisão provêem um comando `add` que diz
-ao sistema para começar a rastrear mudanças em um novo arquivo. O
-comando `add` do git faz algo mais simples e mais poderoso: 'git-add' Ã©
-usado tanto para arquivos novos e arquivos recentemente modificados, e
-em ambos os casos, ele tira o instantâneo dos arquivos dados e armazena
-o conteúdo no Ã­ndice, pronto para inclusão do próximo commit.
-
-Visualizando a história do projeto
------------------------
-
-Em qualquer ponto você pode visualizar a história das suas mudanças
-usando
-
-------------------------------------------------
-$ git log
-------------------------------------------------
-
-Se você também quiser ver a diferença completa a cada passo, use
-
-------------------------------------------------
-$ git log -p
-------------------------------------------------
-
-Geralmente, uma visão geral da mudança Ã© Ãºtil para ter a sensação de
-cada passo
-
-------------------------------------------------
-$ git log --stat --summary
-------------------------------------------------
-
-Gerenciando "branches"/ramos
------------------
-
-Um simples repositório git pode manter múltiplos ramos de
-desenvolvimento. Para criar um novo ramo chamado "experimental", use
-
-------------------------------------------------
-$ git branch experimental
-------------------------------------------------
-
-Se você executar agora
-
-------------------------------------------------
-$ git branch
-------------------------------------------------
-
-você vai obter uma lista de todos os ramos existentes:
-
-------------------------------------------------
-  experimental
-* master
-------------------------------------------------
-
-O ramo "experimental" Ã© o que você acaba de criar, e o ramo "master" Ã© o
-ramo padrão que foi criado pra você automaticamente. O asterisco marca
-o ramo em que você está atualmente; digite
-
-------------------------------------------------
-$ git checkout experimental
-------------------------------------------------
-
-para mudar para o ramo experimental. Agora edite um arquivo, grave a
-mudança, e mude de volta para o ramo master:
-
-------------------------------------------------
-(edita arquivo)
-$ git commit -a
-$ git checkout master
-------------------------------------------------
-
-Verifique que a mudança que você fez não está mais visível, já que ela
-foi feita no ramo experimental e você está de volta ao ramo master.
-
-Você pode fazer uma mudança diferente no ramo master:
-
-------------------------------------------------
-(edit file)
-$ git commit -a
-------------------------------------------------
-
-neste ponto, os dois ramos divergiram, com diferentes mudanças feitas em
-cada um. Para unificar as mudanças feitas no experimental para o
-master, execute
-
-------------------------------------------------
-$ git merge experimental
-------------------------------------------------
-
-Se as mudanças não conflitarem, estará pronto. Se existirem conflitos,
-marcadores serão deixados nos arquivos problemáticos exibindo o
-conflito;
-
-------------------------------------------------
-$ git diff
-------------------------------------------------
-
-vai exibir isto. Após você editar os arquivos para resolver os
-conflitos,
-
-------------------------------------------------
-$ git commit -a
-------------------------------------------------
-
-irá gravar o resultado da unificação. Finalmente,
-
-------------------------------------------------
-$ gitk
-------------------------------------------------
-
-vai mostrar uma bela representação gráfica da história resultante.
-
-Neste ponto você pode remover seu ramo experimental com
-
-------------------------------------------------
-$ git branch -d experimental
-------------------------------------------------
-
-Este comando garante que as mudanças no ramo experimental já estão no
-ramo atual.
-
-Se você desenvolve em um ramo ideia-louca, e se arrepende, você pode
-sempre remover o ramo com
-
--------------------------------------
-$ git branch -D ideia-louca
--------------------------------------
-
-Ramos são baratos e fáceis, então isto Ã© uma boa maneira de experimentar
-alguma coisa.
-
-Usando git para colaboração
----------------------------
-
-Suponha que Alice começou um novo projeto com um repositório git em
-/home/alice/project, e que Bob, que tem um diretório home na mesma
-máquina, quer contribuir.
-
-Bob começa com:
-
-------------------------------------------------
-bob$ git clone /home/alice/project myrepo
-------------------------------------------------
-
-Isso cria um novo diretório "myrepo" contendo um clone do repositório de
-Alice. O clone está no mesmo pé que o projeto original, possuindo sua
-própria cópia da história do projeto original.
-
-Bob então faz algumas mudanças e as grava:
-
-------------------------------------------------
-(editar arquivos)
-bob$ git commit -a
-(repetir conforme necessário)
-------------------------------------------------
-
-Quanto está pronto, ele diz a Alice para puxar as mudanças do
-repositório em /home/bob/myrepo. Ela o faz com:
-
-------------------------------------------------
-alice$ cd /home/alice/project
-alice$ git pull /home/bob/myrepo master
-------------------------------------------------
-
-Isto unifica as mudanças do ramo "master" do Bob ao ramo atual de Alice.
-Se Alice fez suas próprias mudanças no intervalo, ela, então, pode
-precisar corrigir manualmente quaisquer conflitos. (Note que o argumento
-"master" no comando acima Ã©, de fato, desnecessário, já que Ã© o padrão.)
-
-O comando "pull" executa, então, duas operações: ele obtém mudanças de
-um ramo remoto, e, então, as unifica no ramo atual.
-
-Note que, em geral, Alice gostaria que suas mudanças locais fossem
-gravadas antes de iniciar este "pull". Se o trabalho de Bob conflita
-com o que Alice fez desde que suas histórias se ramificaram, Alice irá
-usar seu diretório de trabalho e o Ã­ndice para resolver conflitos, e
-mudanças locais existentes irão interferir com o processo de resolução
-de conflitos (git ainda irá realizar a obtenção mas irá se recusar a
-unificar --- Alice terá que se livrar de suas mudanças locais de alguma
-forma e puxar de novo quando isso acontecer).
-
-Alice pode espiar o que Bob fez sem unificar primeiro, usando o comando
-"fetch"; isto permite Alice inspecionar o que Bob fez, usando um símbolo
-especial "FETCH_HEAD", com o fim de determinar se ele tem alguma coisa
-que vale puxar, assim:
-
-------------------------------------------------
-alice$ git fetch /home/bob/myrepo master
-alice$ git log -p HEAD..FETCH_HEAD
-------------------------------------------------
-
-Esta operação Ã© segura mesmo se Alice tem mudanças locais não gravadas.
-A notação de intervalo "HEAD..FETCH_HEAD" significa mostrar tudo que Ã©
-alcançável de FETCH_HEAD mas exclua tudo o que Ã© alcançável de HEAD.
-Alice já sabe tudo que leva a seu estado atual (HEAD), e revisa o que Bob
-tem em seu estado (FETCH_HEAD) que ela ainda não viu com esse comando.
-
-Se Alice quer visualizar o que Bob fez desde que suas histórias se
-ramificaram, ela pode disparar o seguinte comando:
-
-------------------------------------------------
-$ gitk HEAD..FETCH_HEAD
-------------------------------------------------
-
-Isto usa a mesma notação de intervalo que vimos antes com 'git log'.
-
-Alice pode querer ver o que ambos fizeram desde que ramificaram. Ela
-pode usar a forma com três pontos ao invés da forma com dois pontos:
-
-------------------------------------------------
-$ gitk HEAD...FETCH_HEAD
-------------------------------------------------
-
-Isto significa "mostre tudo que Ã© alcançável de qualquer um deles, mas
-exclua tudo que Ã© alcançável a partir de ambos".
-
-Por favor, note que essas notações de intervalo podem ser usadas tanto
-com gitk quanto com "git log".
-
-Após inspecionar o que Bob fez, se não há nada urgente, Alice pode
-decidir continuar trabalhando sem puxar de Bob. Se a história de Bob
-tem alguma coisa que Alice precisa imediatamente, Alice pode optar por
-separar seu trabalho em progresso primeiro, fazer um "pull", e, então,
-finalmente, retomar seu trabalho em progresso em cima da história
-resultante.
-
-Quando você está trabalhando em um pequeno grupo unido, não Ã© incomum
-interagir com o mesmo repositório várias e várias vezes. Definindo um
-repositório remoto antes de tudo, você pode fazê-lo mais facilmente:
-
-------------------------------------------------
-alice$ git remote add bob /home/bob/myrepo
-------------------------------------------------
-
-Com isso, Alice pode executar a primeira parte da operação "pull" usando
-o comando 'git-fetch' sem unificar suas mudanças com seu próprio ramo,
-usando:
-
--------------------------------------
-alice$ git fetch bob
--------------------------------------
-
-Diferente da forma longa, quando Alice obteve de Bob usando um
-repositório remoto antes definido com 'git-remote', o que foi obtido Ã©
-armazenado em um ramo remoto, neste caso `bob/master`. Então, após isso:
-
--------------------------------------
-alice$ git log -p master..bob/master
--------------------------------------
-
-mostra uma lista de todas as mudanças que Bob fez desde que ramificou do
-ramo master de Alice.
-
-Após examinar essas mudanças, Alice pode unificá-las em seu ramo master:
-
--------------------------------------
-alice$ git merge bob/master
--------------------------------------
-
-Esse `merge` pode também ser feito puxando de seu próprio ramo remoto,
-assim:
-
--------------------------------------
-alice$ git pull . remotes/bob/master
--------------------------------------
-
-Note que 'git pull' sempre unifica ao ramo atual, independente do que
-mais foi passado na linha de comando.
-
-Depois, Bob pode atualizar seu repositório com as Ãºltimas mudanças de
-Alice, usando
-
--------------------------------------
-bob$ git pull
--------------------------------------
-
-Note que ele não precisa dar o caminho do repositório de Alice; quando
-Bob clonou seu repositório, o git armazenou a localização de seu
-repositório na configuração do mesmo, e essa localização Ã© usada
-para puxar:
-
--------------------------------------
-bob$ git config --get remote.origin.url
-/home/alice/project
--------------------------------------
-
-(A configuração completa criada por 'git-clone' Ã© visível usando `git
-config -l`, e a página de manual linkgit:git-config[1] explica o
-significado de cada opção.)
-
-Git também mantém uma cópia limpa do ramo master de Alice sob o nome
-"origin/master":
-
--------------------------------------
-bob$ git branch -r
-  origin/master
--------------------------------------
-
-Se Bob decidir depois em trabalhar em um host diferente, ele ainda pode
-executar clones e puxar usando o protocolo ssh:
-
--------------------------------------
-bob$ git clone alice.org:/home/alice/project myrepo
--------------------------------------
-
-Alternativamente, o git tem um protocolo nativo, ou pode usar rsync ou
-http; veja linkgit:git-pull[1] para detalhes.
-
-Git pode também ser usado em um modo parecido com CVS, com um
-repositório central para o qual vários usuários empurram modificações;
-veja linkgit:git-push[1] e linkgit:gitcvs-migration[7].
-
-Explorando história
------------------
-
-A história no git Ã© representada como uma série de commits
-interrelacionados. Nós já vimos que o comando 'git-log' pode listar
-esses commits. Note que a primeira linha de cada entrada no log também
-dá o nome para o commit:
-
--------------------------------------
-$ git log
-commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
-Author: Junio C Hamano <junkio@cox.net>
-Date:   Tue May 16 17:18:22 2006 -0700
-
-    merge-base: Clarify the comments on post processing.
--------------------------------------
-
-Nós podemos dar este nome ao 'git-show' para ver os detalhes sobre este
-commit.
-
--------------------------------------
-$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
--------------------------------------
-
-Mas há outras formas de se referir aos commits. Você pode usar qualquer
-parte inicial do nome que seja longo o bastante para identificar
-unicamente o commit:
-
--------------------------------------
-$ git show c82a22c39c  # os primeiros caracteres do nome são o bastante
-                       # usualmente
-$ git show HEAD                # a ponta do ramo atual
-$ git show experimental        # a ponta do ramo "experimental"
--------------------------------------
-
-Todo commit normalmente tem um commit "pai" que aponta para o estado
-anterior do projeto:
-
--------------------------------------
-$ git show HEAD^  # para ver o pai de HEAD
-$ git show HEAD^^ # para ver o avô de HEAD
-$ git show HEAD~4 # para ver o trisavô de HEAD
--------------------------------------
-
-Note que commits de unificação podem ter mais de um pai:
-
--------------------------------------
-$ git show HEAD^1 # mostra o primeiro pai de HEAD (o mesmo que HEAD^)
-$ git show HEAD^2 # mostra o segundo pai de HEAD
--------------------------------------
-
-Você também pode dar aos commits nomes Ã  sua escolha; após executar
-
--------------------------------------
-$ git tag v2.5 1b2e1d63ff
--------------------------------------
-
-você pode se referir a 1b2e1d63ff pelo nome "v2.5". Se você pretende
-compartilhar esse nome com outras pessoas (por exemplo, para identificar
-uma versão de lançamento), você deveria criar um objeto "tag", e talvez
-assiná-lo; veja linkgit:git-tag[1] para detalhes.
-
-Qualquer comando git que precise conhecer um commit pode receber
-quaisquer desses nomes. Por exemplo:
-
--------------------------------------
-$ git diff v2.5 HEAD    # compara o HEAD atual com v2.5
-$ git branch stable v2.5 # inicia um novo ramo chamado "stable" baseado
-                        # em v2.5
-$ git reset --hard HEAD^ # reseta seu ramo atual e seu diretório de
-                        # trabalho a seu estado em HEAD^
--------------------------------------
-
-Seja cuidadoso com o Ãºltimo comando: além de perder quaisquer mudanças
-em seu diretório de trabalho, ele também remove todos os commits
-posteriores desse ramo. Se esse ramo Ã© o Ãºnico ramo contendo esses
-commits, eles serão perdidos. Também, não use 'git-reset' num ramo
-publicamente visível de onde outros desenvolvedores puxam, já que vai
-forçar unificações desnecessárias para que outros desenvolvedores limpem
-a história. Se você precisa desfazer mudanças que você empurrou, use
-'git-revert' no lugar.
-
-O comando 'git-grep' pode buscar strings em qualquer versão de seu
-projeto, então
-
--------------------------------------
-$ git grep "hello" v2.5
--------------------------------------
-
-procura por todas as ocorrências de "hello" em v2.5.
-
-Se você deixar de fora o nome do commit, 'git-grep' irá procurar
-quaisquer dos arquivos que ele gerencia no diretório corrente. Então
-
--------------------------------------
-$ git grep "hello"
--------------------------------------
-
-é uma forma rápida de buscar somente os arquivos que são rastreados pelo
-git.
-
-Muitos comandos git também recebem um conjunto de commits, o que pode
-ser especificado de várias formas. Aqui estão alguns exemplos com 'git-log':
-
--------------------------------------
-$ git log v2.5..v2.6            # commits entre v2.5 e v2.6
-$ git log v2.5..                # commits desde v2.5
-$ git log --since="2 weeks ago" # commits das Ãºltimas 2 semanas
-$ git log v2.5.. Makefile       # commits desde v2.5 que modificam
-                               # Makefile
--------------------------------------
-
-Você também pode dar ao 'git-log' um "intervalo" de commits onde o
-primeiro não Ã© necessariamente um ancestral do segundo; por exemplo, se
-as pontas dos ramos "stable" e "master" divergiram de um commit
-comum algum tempo atrás, então
-
--------------------------------------
-$ git log stable..master
--------------------------------------
-
-irá listar os commits feitos no ramo "master" mas não no ramo
-"stable", enquanto
-
--------------------------------------
-$ git log master..stable
--------------------------------------
-
-irá listar a lista de commits feitos no ramo "stable" mas não no ramo
-"master".
-
-O comando 'git-log' tem uma fraqueza: ele precisa mostrar os commits em
-uma lista. Quando a história tem linhas de desenvolvimento que
-divergiram e então foram unificadas novamente, a ordem em que 'git-log'
-apresenta essas mudanças Ã© irrelevante.
-
-A maioria dos projetos com múltiplos contribuidores (como o kernel
-Linux, ou o próprio git) tem unificações frequentes, e 'gitk' faz um
-trabalho melhor de visualizar sua história. Por exemplo,
-
--------------------------------------
-$ gitk --since="2 weeks ago" drivers/
--------------------------------------
-
-permite a você navegar em quaisquer commits desde as Ãºltimas duas semanas
-de commits que modificaram arquivos sob o diretório "drivers". (Nota:
-você pode ajustar as fontes do gitk segurando a tecla control enquanto
-pressiona "-" ou "+".)
-
-Finalmente, a maioria dos comandos que recebem nomes de arquivo permitirão
-também, opcionalmente, preceder qualquer nome de arquivo por um
-commit, para especificar uma versão particular do arquivo:
-
--------------------------------------
-$ git diff v2.5:Makefile HEAD:Makefile.in
--------------------------------------
-
-Você pode usar 'git-show' para ver tal arquivo:
-
--------------------------------------
-$ git show v2.5:Makefile
--------------------------------------
-
-Próximos passos
-----------
-
-Este tutorial deve ser o bastante para operar controle de revisão
-distribuído básico para seus projetos. No entanto, para entender
-plenamente a profundidade e o poder do git você precisa entender duas
-idéias simples nas quais ele se baseia:
-
-  * A base de objetos Ã© um sistema bem elegante usado para armazenar a
-    história de seu projeto--arquivos, diretórios, e commits.
-
-  * O arquivo de Ã­ndice Ã© um cache do estado de uma Ã¡rvore de diretório,
-    usado para criar commits, restaurar diretórios de trabalho, e
-    armazenar as várias Ã¡rvores envolvidas em uma unificação.
-
-A parte dois deste tutorial explica a base de objetos, o arquivo de
-índice, e algumas outras coisinhas que você vai precisar pra usar o
-máximo do git. Você pode encontrá-la em linkgit:gittutorial-2[7].
-
-Se você não quiser continuar com o tutorial agora nesse momento, algumas
-outras digressões que podem ser interessantes neste ponto são:
-
-  * linkgit:git-format-patch[1], linkgit:git-am[1]: Estes convertem
-    séries de commits em patches para email, e vice-versa, Ãºteis para
-    projetos como o kernel Linux que dependem fortemente de patches
-    enviados por email.
-
-  * linkgit:git-bisect[1]: Quando há uma regressão em seu projeto, uma
-    forma de rastrear um bug Ã© procurando pela história para encontrar o
-    commit culpado. Git bisect pode ajudar a executar uma busca binária
-    por esse commit. Ele Ã© inteligente o bastante para executar uma
-    busca próxima da Ã³tima mesmo no caso de uma história complexa
-    não-linear com muitos ramos unificados.
-
-  * link:everyday.html[GIT diariamente com 20 e tantos comandos]
-
-  * linkgit:gitcvs-migration[7]: Git para usuários de CVS.
-
-VEJA TAMBÉM
---------
-linkgit:gittutorial-2[7],
-linkgit:gitcvs-migration[7],
-linkgit:gitcore-tutorial[7],
-linkgit:gitglossary[7],
-linkgit:git-help[1],
-link:everyday.html[git diariamente],
-link:user-manual.html[O Manual do Usuário git]
-
-GIT
----
-Parte da suite linkgit:git[1].
index 43dbe09f735525b0a1549ccfb4de2f2ca87252a0..542946b1ba701069837b702cbd8fe8079cecf56d 100644 (file)
@@ -5,7 +5,9 @@ Dynamically growing an array using realloc() is error prone and boring.
 
 Define your array with:
 
-* a pointer (`ary`) that points at the array, initialized to `NULL`;
+* a pointer (`item`) that points at the array, initialized to `NULL`
+  (although please name the variable based on its contents, not on its
+  type);
 
 * an integer variable (`alloc`) that keeps track of how big the current
   allocation is, initialized to `0`;
@@ -13,22 +15,22 @@ Define your array with:
 * another integer variable (`nr`) to keep track of how many elements the
   array currently has, initialized to `0`.
 
-Then before adding `n`th element to the array, call `ALLOC_GROW(ary, n,
+Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
 alloc)`.  This ensures that the array can hold at least `n` elements by
 calling `realloc(3)` and adjusting `alloc` variable.
 
 ------------
-sometype *ary;
+sometype *item;
 size_t nr;
 size_t alloc
 
 for (i = 0; i < nr; i++)
-       if (we like ary[i] already)
+       if (we like item[i] already)
                return;
 
 /* we did not like any existing one, so add one */
-ALLOC_GROW(ary, nr + 1, alloc);
-ary[nr++] = value you like;
+ALLOC_GROW(item, nr + 1, alloc);
+item[nr++] = value you like;
 ------------
 
 You are responsible for updating the `nr` variable.
diff --git a/Documentation/technical/api-command.txt b/Documentation/technical/api-command.txt
deleted file mode 100644 (file)
index d3b9781..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-Integrating new subcommands
-===========================
-
-This is how-to documentation for people who want to add extension
-commands to git.  It should be read alongside api-builtin.txt.
-
-Runtime environment
--------------------
-
-git subcommands are standalone executables that live in the git exec
-path, normally /usr/lib/git-core.  The git executable itself is a
-thin wrapper that knows where the subcommands live, and runs them by
-passing command-line arguments to them.
-
-(If "git foo" is not found in the git exec path, the wrapper
-will look in the rest of your $PATH for it.  Thus, it's possible
-to write local git extensions that don't live in system space.)
-
-Implementation languages
-------------------------
-
-Most subcommands are written in C or shell.  A few are written in
-Perl.
-
-While we strongly encourage coding in portable C for portability,
-these specific scripting languages are also acceptable.  We won't
-accept more without a very strong technical case, as we don't want
-to broaden the git suite's required dependencies.  Import utilities,
-surgical tools, remote helpers and other code at the edges of the
-git suite are more lenient and we allow Python (and even Tcl/tk),
-but they should not be used for core functions.
-
-This may change in the future.  Especially Python is not allowed in
-core because we need better Python integration in the git Windows
-installer before we can be confident people in that environment
-won't experience an unacceptably large loss of capability.
-
-C commands are normally written as single modules, named after the
-command, that link a collection of functions called libgit.  Thus,
-your command 'git-foo' would normally be implemented as a single
-"git-foo.c" (or "builtin/foo.c" if it is to be linked to the main
-binary); this organization makes it easy for people reading the code
-to find things.
-
-See the CodingGuidelines document for other guidance on what we consider
-good practice in C and shell, and api-builtin.txt for the support
-functions available to built-in commands written in C.
-
-What every extension command needs
-----------------------------------
-
-You must have a man page, written in asciidoc (this is what git help
-followed by your subcommand name will display).  Be aware that there is
-a local asciidoc configuration and macros which you should use.  It's
-often helpful to start by cloning an existing page and replacing the
-text content.
-
-You must have a test, written to report in TAP (Test Anything Protocol).
-Tests are executables (usually shell scripts) that live in the 't'
-subdirectory of the tree.  Each test name begins with 't' and a sequence
-number that controls where in the test sequence it will be executed;
-conventionally the rest of the name stem is that of the command
-being tested.
-
-Read the file t/README to learn more about the conventions to be used
-in writing tests, and the test support library.
-
-Integrating a command
----------------------
-
-Here are the things you need to do when you want to merge a new
-subcommand into the git tree.
-
-1. Don't forget to sign off your patch!
-
-2. Append your command name to one of the variables BUILTIN_OBJS,
-EXTRA_PROGRAMS, SCRIPT_SH, SCRIPT_PERL or SCRIPT_PYTHON.
-
-3. Drop its test in the t directory.
-
-4. If your command is implemented in an interpreted language with a
-p-code intermediate form, make sure .gitignore in the main directory
-includes a pattern entry that ignores such files.  Python .pyc and
-.pyo files will already be covered.
-
-5. If your command has any dependency on a particular version of
-your language, document it in the INSTALL file.
-
-6. There is a file command-list.txt in the distribution main directory
-that categorizes commands by type, so they can be listed in appropriate
-subsections in the documentation's summary command list.  Add an entry
-for yours.  To understand the categories, look at git-cmmands.txt
-in the main directory.
-
-7. Give the maintainer one paragraph to include in the RelNotes file
-to describe the new feature; a good place to do so is in the cover
-letter [PATCH 0/n].
-
-That's all there is to it.
index d6fc90ac7eb210bd492057422748817a59cfc2a3..18142b6d29283bbf6e325ce71d50761a3f50a227 100644 (file)
@@ -33,11 +33,11 @@ The following utility functions are wrappers around `graph_next_line()` and
 They can all be called with a NULL graph argument, in which case no graph
 output will be printed.
 
-* `graph_show_commit()` calls `graph_next_line()` until it returns non-zero.
-  This prints all graph lines up to, and including, the line containing this
-  commit.  Output is printed to stdout.  The last line printed does not contain
-  a terminating newline.  This should not be called if the commit line has
-  already been printed, or it will loop forever.
+* `graph_show_commit()` calls `graph_next_line()` and
+  `graph_is_commit_finished()` until one of them return non-zero.  This prints
+  all graph lines up to, and including, the line containing this commit.
+  Output is printed to stdout.  The last line printed does not contain a
+  terminating newline.
 
 * `graph_show_oneline()` calls `graph_next_line()` and prints the result to
   stdout.  The line printed does not contain a terminating newline.
index af7cc2e395f1399830f9eacc52468376b216fb86..730cfacf783ef26b408f22c13599420db46e28b4 100644 (file)
@@ -11,5 +11,3 @@ documents them.
 ////////////////////////////////////////////////////////////////
 // table of contents end
 ////////////////////////////////////////////////////////////////
-
-2007-11-24
index f18b4f4817448530a5adbe2c8835bb7791add42a..5d7d7f2d32f58f8682ca5efb2fd98fe7e74247dd 100644 (file)
@@ -55,10 +55,8 @@ The functions above do the following:
   non-zero.
 
 . If the program terminated due to a signal, then the return value is the
-  signal number - 128, ie. it is negative and so indicates an unusual
-  condition; a diagnostic is printed. This return value can be passed to
-  exit(2), which will report the same code to the parent process that a
-  POSIX shell's $? would report for a program that died from the signal.
+  signal number + 128, ie. the same value that a POSIX shell's $? would
+  report.  A diagnostic is printed.
 
 
 `start_async`::
index 7386bcab3ec30a06f4663c953fa46e78ed26c07b..20be3488349c2ddbafbd90c0200f2a7d3862a12f 100644 (file)
@@ -82,14 +82,6 @@ Functions
        call free() on the util members of any items that have to be
        deleted.  Preserve the order of the items that are retained.
 
-`string_list_longest_prefix`::
-
-       Return the longest string within a string_list that is a
-       prefix (in the sense of prefixcmp()) of the specified string,
-       or NULL if no such prefix exists.  This function does not
-       require the string_list to be sorted (it does a linear
-       search).
-
 `print_string_list`::
 
        Dump a string_list to stdout, useful mainly for debugging purposes. It
index 57d6f915b143765b9e58b3793f14795ddab71200..73241548381fcb0b3c0dbd2cb09f9526a64e637d 100644 (file)
@@ -161,8 +161,9 @@ GIT index format
     this span of index as a tree.
 
   An entry can be in an invalidated state and is represented by having
-  -1 in the entry_count field. In this case, there is no object name
-  and the next entry starts immediately after the newline.
+  a negative number in the entry_count field. In this case, there is no
+  object name and the next entry starts immediately after the newline.
+  When writing an invalid entry, -1 should always be used as entry_count.
 
   The entries are written out in the top-down, depth-first order.  The
   first entry represents the root level of the repository, followed by the
index 1d15ee7e5209f93a387db348dcccd6abd9cb306f..cea5462ff83366dc3307be37162c57f97cb636c4 100644 (file)
@@ -55,7 +55,7 @@ may be used:
 
 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.
+invoked. See linkgit:gitremote-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 1b377dc20736320fb442255c88310d62078b21e0..52c8523c7dc1048f0f8f04b334071d4bfefee685 100644 (file)
@@ -782,7 +782,7 @@ e05db0fd4f31dde7005f075a84f96b360d05984b
 
 Or you could recall that the ... operator selects all commits
 contained reachable from either one reference or the other but not
-both: so
+both; so
 
 -------------------------------------------------
 $ git log origin...master
@@ -931,11 +931,20 @@ The linkgit:git-archive[1] command can create a tar or zip archive from
 any version of a project; for example:
 
 -------------------------------------------------
-$ git archive --format=tar --prefix=project/ HEAD | gzip >latest.tar.gz
+$ git archive -o latest.tar.gz --prefix=project/ HEAD
 -------------------------------------------------
 
-will use HEAD to produce a tar archive in which each filename is
-preceded by "project/".
+will use HEAD to produce a gzipped tar archive in which each filename
+is preceded by `project/`.  The output file format is inferred from
+the output file extension if possible, see linkgit:git-archive[1] for
+details.
+
+Versions of Git older than 1.7.7 don't know about the 'tar.gz' format,
+you'll need to use gzip explicitly:
+
+-------------------------------------------------
+$ git archive --format=tar --prefix=project/ HEAD | gzip >latest.tar.gz
+-------------------------------------------------
 
 If you're releasing a new version of a software project, you may want
 to simultaneously make a changelog to include in the release
@@ -991,9 +1000,16 @@ Developing with git
 Telling git your name
 ---------------------
 
-Before creating any commits, you should introduce yourself to git.  The
-easiest way to do so is to make sure the following lines appear in a
-file named .gitconfig in your home directory:
+Before creating any commits, you should introduce yourself to Git.
+The easiest way to do so is to use linkgit:git-config[1]:
+
+------------------------------------------------
+$ git config --global user.name 'Your Name Comes Here'
+$ git config --global user.email 'you@yourdomain.example.com'
+------------------------------------------------
+
+Which will add the following to a file named `.gitconfig` in your
+home directory:
 
 ------------------------------------------------
 [user]
@@ -1001,8 +1017,9 @@ file named .gitconfig in your home directory:
        email = you@yourdomain.example.com
 ------------------------------------------------
 
-(See the "CONFIGURATION FILE" section of linkgit:git-config[1] for
-details on the configuration file.)
+See the "CONFIGURATION FILE" section of linkgit:git-config[1] for
+details on the configuration file.  The file is plain text, so you can
+also edit it with your favorite editor.
 
 
 [[creating-a-new-repository]]
@@ -1561,18 +1578,12 @@ $ git stash pop
 Ensuring good performance
 -------------------------
 
-On large repositories, git depends on compression to keep the history
-information from taking up too much space on disk or in memory.
-
-This compression is not performed automatically.  Therefore you
-should occasionally run linkgit:git-gc[1]:
-
--------------------------------------------------
-$ git gc
--------------------------------------------------
-
-to recompress the archive.  This can be very time-consuming, so
-you may prefer to run `git gc` when you are not doing other work.
+On large repositories, Git depends on compression to keep the history
+information from taking up too much space on disk or in memory.  Some
+git commands may automatically run linkgit:git-gc[1], so you don't
+have to worry about running it manually.  However, compressing a large
+repository may take a while, so you may want to call `gc` explicitly
+to avoid automatic compression kicking in when it is not convenient.
 
 
 [[ensuring-reliability]]
@@ -1931,11 +1942,11 @@ linkgit:git-daemon[1] man page for details.  (See especially the
 examples section.)
 
 [[exporting-via-http]]
-Exporting a git repository via http
+Exporting a git repository via HTTP
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The git protocol gives better performance and reliability, but on a
-host with a web server set up, http exports may be simpler to set up.
+host with a web server set up, HTTP exports may be simpler to set up.
 
 All you need to do is place the newly created bare git repository in
 a directory that is exported by the web server, and make some
@@ -1961,7 +1972,7 @@ $ git clone http://yourserver.com/~you/proj.git
 (See also
 link:howto/setup-git-server-over-http.txt[setup-git-server-over-http]
 for a slightly more sophisticated setup using WebDAV which also
-allows pushing over http.)
+allows pushing over HTTP.)
 
 [[pushing-changes-to-a-public-repository]]
 Pushing changes to a public repository
@@ -1998,16 +2009,21 @@ will not be updated by the push.  This may lead to unexpected results if
 the branch you push to is the currently checked-out branch!
 
 As with `git fetch`, you may also set up configuration options to
-save typing; so, for example, after
+save typing; so, for example:
+
+-------------------------------------------------
+$ git remote add public-repo ssh://yourserver.com/~you/proj.git
+-------------------------------------------------
+
+adds the following to `.git/config`:
 
 -------------------------------------------------
-$ cat >>.git/config <<EOF
 [remote "public-repo"]
-       url = ssh://yourserver.com/~you/proj.git
-EOF
+       url = yourserver.com:proj.git
+       fetch = +refs/heads/*:refs/remotes/example/*
 -------------------------------------------------
 
-you should be able to perform the above push with just
+which lets you do the same push with just
 
 -------------------------------------------------
 $ git push public-repo master
@@ -2046,6 +2062,13 @@ branch name with a plus sign:
 $ git push ssh://yourserver.com/~you/proj.git +master
 -------------------------------------------------
 
+Note the addition of the `+` sign.  Alternatively, you can use the
+`-f` flag to force the remote update, as in:
+
+-------------------------------------------------
+$ git push -f ssh://yourserver.com/~you/proj.git master
+-------------------------------------------------
+
 Normally whenever a branch head in a public repository is modified, it
 is modified to point to a descendant of the commit that it pointed to
 before.  By forcing a push in this situation, you break that convention.
@@ -2850,48 +2873,34 @@ branch.master.merge=refs/heads/master
 
 If there are other repositories that you also use frequently, you can
 create similar configuration options to save typing; for example,
-after
 
 -------------------------------------------------
-$ git config remote.example.url git://example.com/proj.git
+$ git remote add example git://example.com/proj.git
 -------------------------------------------------
 
-then the following two commands will do the same thing:
+adds the following to `.git/config`:
 
 -------------------------------------------------
-$ git fetch git://example.com/proj.git master:refs/remotes/example/master
-$ git fetch example master:refs/remotes/example/master
+[remote "example"]
+       url = git://example.com/proj.git
+       fetch = +refs/heads/*:refs/remotes/example/*
 -------------------------------------------------
 
-Even better, if you add one more option:
+Also note that the above configuration can be performed by directly
+editing the file `.git/config` instead of using linkgit:git-remote[1].
 
--------------------------------------------------
-$ git config remote.example.fetch master:refs/remotes/example/master
--------------------------------------------------
-
-then the following commands will all do the same thing:
+After configuring the remote, the following three commands will do the
+same thing:
 
 -------------------------------------------------
-$ git fetch git://example.com/proj.git master:refs/remotes/example/master
-$ git fetch example master:refs/remotes/example/master
+$ git fetch git://example.com/proj.git +refs/heads/*:refs/remotes/example/*
+$ git fetch example +refs/heads/*:refs/remotes/example/*
 $ git fetch example
 -------------------------------------------------
 
-You can also add a "+" to force the update each time:
-
--------------------------------------------------
-$ git config remote.example.fetch +master:refs/remotes/example/master
--------------------------------------------------
-
-Don't do this unless you're sure you won't mind "git fetch" possibly
-throwing away commits on 'example/master'.
-
-Also note that all of the above configuration can be performed by
-directly editing the file .git/config instead of using
-linkgit:git-config[1].
-
 See linkgit:git-config[1] for more details on the configuration
-options mentioned above.
+options mentioned above and linkgit:git-fetch[1] for more details on
+the refspec syntax.
 
 
 [[git-concepts]]
@@ -3396,7 +3405,7 @@ $ git log --raw --all
 ------------------------------------------------
 
 and just looked for the sha of the missing object (4b9458b..) in that
-whole thing. It's up to you - git does *have* a lot of information, it is
+whole thing. It's up to you--Git does *have* a lot of information, it is
 just missing one particular blob version.
 
 [[the-index]]
index 1a9e4a20da78de93b7769eb18a7b3258dbde8ede..dcd3595f278439c267d8e7f9725efa2147bf1f15 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.1-rc2
+DEF_VER=v1.8.1.4
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 28f34bd254d8b0be484b5aedce1c35079fd32cc4..2dc3b61d1fe1b675377a6ece96feaddf8a0721ba 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -131,8 +131,9 @@ Issues of note:
          use English. Under autoconf the configure script will do this
          automatically if it can't find libintl on the system.
 
-       - Python version 2.6 or later is needed to use the git-p4
-         interface to Perforce.
+       - Python version 2.4 or later (but not 3.x, which is not
+         supported by Perforce) is needed to use the git-p4 interface
+         to Perforce.
 
  - Some platform specific issues are dealt with Makefile rules,
    but depending on your specific installation, you may not
index 736ecd45b58da32575cc20019d41a2b178843a09..4bb3cf13673249d893b450352a27e70f837aa7b8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -273,6 +273,10 @@ all::
 #
 # Define NO_REGEX if you have no or inferior regex support in your C library.
 #
+# Define CYGWIN_V15_WIN32API if you are using Cygwin v1.7.x but are not
+# using the current w32api packages. The recommended approach, however,
+# is to update your installation if compilation errors occur.
+#
 # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
 # user.
 #
@@ -649,7 +653,7 @@ LIB_H += list-objects.h
 LIB_H += ll-merge.h
 LIB_H += log-tree.h
 LIB_H += mailmap.h
-LIB_H += merge-file.h
+LIB_H += merge-blobs.h
 LIB_H += merge-recursive.h
 LIB_H += mergesort.h
 LIB_H += notes-cache.h
@@ -765,7 +769,7 @@ LIB_OBJS += log-tree.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge.o
-LIB_OBJS += merge-file.o
+LIB_OBJS += merge-blobs.o
 LIB_OBJS += merge-recursive.o
 LIB_OBJS += mergesort.o
 LIB_OBJS += name-hash.o
@@ -1471,7 +1475,8 @@ endif
 
 ifeq ($(COMPUTE_HEADER_DEPENDENCIES),auto)
 dep_check = $(shell $(CC) $(ALL_CFLAGS) \
-       -c -MF /dev/null -MMD -MP -x c /dev/null -o /dev/null 2>&1; \
+       -c -MF /dev/null -MQ /dev/null -MMD -MP \
+       -x c /dev/null -o /dev/null 2>&1; \
        echo $$?)
 ifeq ($(dep_check),0)
 override COMPUTE_HEADER_DEPENDENCIES = yes
@@ -2245,7 +2250,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
 endif # NO_PERL
 
 ifndef NO_PYTHON
-$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX
+$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
 $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
@@ -2275,8 +2280,14 @@ configure: configure.ac GIT-VERSION-FILE
        $(RM) $<+
 
 ifdef AUTOCONFIGURED
-config.status: configure
-       $(QUIET_GEN)if test -f config.status; then \
+# We avoid depending on 'configure' here, because it gets rebuilt
+# every time GIT-VERSION-FILE is modified, only to update the embedded
+# version number string, which config.status does not care about.  We
+# do want to recheck when the platform/environment detection logic
+# changes, hence this depends on configure.ac.
+config.status: configure.ac
+       $(QUIET_GEN)$(MAKE) configure && \
+       if test -f config.status; then \
          ./config.status --recheck; \
        else \
          ./configure; \
@@ -2319,7 +2330,7 @@ $(dep_dirs):
 
 missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
 dep_file = $(dir $@).depend/$(notdir $@).d
-dep_args = -MF $(dep_file) -MMD -MP
+dep_args = -MF $(dep_file) -MQ $@ -MMD -MP
 ifdef CHECK_HEADER_DEPENDENCIES
 $(error cannot compute header dependencies outside a normal build. \
 Please unset CHECK_HEADER_DEPENDENCIES and try again)
@@ -2636,6 +2647,18 @@ GIT-GUI-VARS: FORCE
             fi
 endif
 
+### Detect Python interpreter path changes
+ifndef NO_PYTHON
+TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)')
+
+GIT-PYTHON-VARS: FORCE
+       @VARS='$(TRACK_PYTHON)'; \
+           if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
+               echo 1>&2 "    * new Python interpreter location"; \
+               echo "$$VARS" >$@; \
+            fi
+endif
+
 test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
 
 all:: $(TEST_PROGRAMS) $(test_bindir_programs)
@@ -2911,7 +2934,7 @@ ifndef NO_TCLTK
        $(MAKE) -C git-gui clean
 endif
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
-       $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES
+       $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS
 
 .PHONY: all install profile-clean clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --git a/README b/README
index d2690ec8dc6e5f054c33a5f3b4c26f6ad038706d..a960ca8f28d6b5a50872f69e65fbff741cde4c02 100644 (file)
--- a/README
+++ b/README
@@ -19,9 +19,10 @@ Git is a fast, scalable, distributed revision control system with an
 unusually rich command set that provides both high-level operations
 and full access to internals.
 
-Git is an Open Source project covered by the GNU General Public License.
-It was originally written by Linus Torvalds with help of a group of
-hackers around the net. It is currently maintained by Junio C Hamano.
+Git is an Open Source project covered by the GNU General Public
+License version 2 (some parts of it are under different licenses,
+compatible with the GPLv2). It was originally written by Linus
+Torvalds with help of a group of hackers around the net.
 
 Please read the file INSTALL for installation instructions.
 
@@ -46,11 +47,10 @@ requests, comments and patches to git@vger.kernel.org (read
 Documentation/SubmittingPatches for instructions on patch submission).
 To subscribe to the list, send an email with just "subscribe git" in
 the body to majordomo@vger.kernel.org. The mailing list archives are
-available at http://marc.theaimsgroup.com/?l=git and other archival
-sites.
-
-The messages titled "A note from the maintainer", "What's in
-git.git (stable)" and "What's cooking in git.git (topics)" and
-the discussion following them on the mailing list give a good
-reference for project status, development direction and
-remaining tasks.
+available at http://news.gmane.org/gmane.comp.version-control.git/,
+http://marc.info/?l=git and other archival sites.
+
+The maintainer frequently sends the "What's cooking" reports that
+list the current status of various development topics to the mailing
+list.  The discussion following them give a good reference for
+project status, development direction and remaining tasks.
index 28607146f3fec3b69cf5edacf2727e37ca2c89de..ad613ead7bfedefeca6e3e49bc0ba9349702aa44 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.1.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.1.4.txt
\ No newline at end of file
index 05f2d7934878a832f5a2efdf4222c16223050853..40cdc46219d4eba87ba947d9f5556eb80dfdfa9b 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -15,16 +15,34 @@ int is_directory(const char *path)
 #define MAXDEPTH 5
 
 /*
- * Use this to get the real path, i.e. resolve links. If you want an
- * absolute path but don't mind links, use absolute_path.
+ * Return the real path (i.e., absolute path, with symlinks resolved
+ * and extra slashes removed) equivalent to the specified path.  (If
+ * you want an absolute path but don't mind links, use
+ * absolute_path().)  The return value is a pointer to a static
+ * buffer.
+ *
+ * The input and all intermediate paths must be shorter than MAX_PATH.
+ * The directory part of path (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.  If die_on_error is set, then die with an
+ * informative error message if there is a problem.  Otherwise, return
+ * NULL on errors (without generating any output).
  *
  * If path is our buffer, then return path, as it's already what the
  * user wants.
  */
-const char *real_path(const char *path)
+static const char *real_path_internal(const char *path, int die_on_error)
 {
        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+       char *retval = NULL;
+
+       /*
+        * If we have to temporarily chdir(), store the original CWD
+        * here so that we can chdir() back to it at the end of the
+        * function:
+        */
        char cwd[1024] = "";
+
        int buf_index = 1;
 
        int depth = MAXDEPTH;
@@ -35,11 +53,19 @@ const char *real_path(const char *path)
        if (path == buf || path == next_buf)
                return path;
 
-       if (!*path)
-               die("The empty string is not a valid path");
+       if (!*path) {
+               if (die_on_error)
+                       die("The empty string is not a valid path");
+               else
+                       goto error_out;
+       }
 
-       if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
-               die ("Too long path: %.*s", 60, path);
+       if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
+               if (die_on_error)
+                       die("Too long path: %.*s", 60, path);
+               else
+                       goto error_out;
+       }
 
        while (depth--) {
                if (!is_directory(buf)) {
@@ -54,20 +80,36 @@ const char *real_path(const char *path)
                }
 
                if (*buf) {
-                       if (!*cwd && !getcwd(cwd, sizeof(cwd)))
-                               die_errno ("Could not get current working directory");
+                       if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
+                               if (die_on_error)
+                                       die_errno("Could not get current working directory");
+                               else
+                                       goto error_out;
+                       }
 
-                       if (chdir(buf))
-                               die_errno ("Could not switch to '%s'", buf);
+                       if (chdir(buf)) {
+                               if (die_on_error)
+                                       die_errno("Could not switch to '%s'", buf);
+                               else
+                                       goto error_out;
+                       }
+               }
+               if (!getcwd(buf, PATH_MAX)) {
+                       if (die_on_error)
+                               die_errno("Could not get current working directory");
+                       else
+                               goto error_out;
                }
-               if (!getcwd(buf, PATH_MAX))
-                       die_errno ("Could not get current working directory");
 
                if (last_elem) {
                        size_t len = strlen(buf);
-                       if (len + strlen(last_elem) + 2 > PATH_MAX)
-                               die ("Too long path name: '%s/%s'",
-                                               buf, last_elem);
+                       if (len + strlen(last_elem) + 2 > PATH_MAX) {
+                               if (die_on_error)
+                                       die("Too long path name: '%s/%s'",
+                                           buf, last_elem);
+                               else
+                                       goto error_out;
+                       }
                        if (len && !is_dir_sep(buf[len-1]))
                                buf[len++] = '/';
                        strcpy(buf + len, last_elem);
@@ -77,10 +119,18 @@ const char *real_path(const char *path)
 
                if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
                        ssize_t len = readlink(buf, next_buf, PATH_MAX);
-                       if (len < 0)
-                               die_errno ("Invalid symlink '%s'", buf);
-                       if (PATH_MAX <= len)
-                               die("symbolic link too long: %s", buf);
+                       if (len < 0) {
+                               if (die_on_error)
+                                       die_errno("Invalid symlink '%s'", buf);
+                               else
+                                       goto error_out;
+                       }
+                       if (PATH_MAX <= len) {
+                               if (die_on_error)
+                                       die("symbolic link too long: %s", buf);
+                               else
+                                       goto error_out;
+                       }
                        next_buf[len] = '\0';
                        buf = next_buf;
                        buf_index = 1 - buf_index;
@@ -89,10 +139,23 @@ const char *real_path(const char *path)
                        break;
        }
 
+       retval = buf;
+error_out:
+       free(last_elem);
        if (*cwd && chdir(cwd))
                die_errno ("Could not change back to '%s'", cwd);
 
-       return buf;
+       return retval;
+}
+
+const char *real_path(const char *path)
+{
+       return real_path_internal(path, 1);
+}
+
+const char *real_path_if_valid(const char *path)
+{
+       return real_path_internal(path, 0);
 }
 
 static const char *get_pwd_cwd(void)
index 0ba3f25cf579d6629566a39d4d5ac19b51293ed5..d1cce46e3310d64af32b231de697449ae90ddccf 100644 (file)
@@ -153,6 +153,8 @@ static unsigned int ustar_header_chksum(const struct ustar_header *header)
 static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
 {
        size_t i = pathlen;
+       if (i > 1 && path[i - 1] == '/')
+               i--;
        if (i > maxlen)
                i = maxlen;
        do {
index 55f66b4060c64789bdb443f6c71f82a75ef22d0b..d3aef532b7e4b844f2ac9995b2e987d378737079 100644 (file)
@@ -240,7 +240,7 @@ static int write_zip_entry(struct archiver_args *args,
                        (mode & 0111) ? ((mode) << 16) : 0;
                if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
                        method = 8;
-               compressed_size = size;
+               compressed_size = (method == 0) ? size : 0;
 
                if (S_ISREG(mode) && type == OBJ_BLOB && !args->convert &&
                    size > big_file_threshold) {
@@ -313,10 +313,7 @@ static int write_zip_entry(struct archiver_args *args,
        copy_le16(header.compression_method, method);
        copy_le16(header.mtime, zip_time);
        copy_le16(header.mdate, zip_date);
-       if (flags & ZIP_STREAM)
-               set_zip_header_data_desc(&header, 0, 0, 0);
-       else
-               set_zip_header_data_desc(&header, size, compressed_size, crc);
+       set_zip_header_data_desc(&header, size, compressed_size, crc);
        copy_le16(header.filename_length, pathlen);
        copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE);
        write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
index 466640479ecb332d8d06f6f26254023eb6e22c85..93e00bb4ae8ff9637be9e55fd41536b8837c3ba2 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -120,6 +120,8 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        strbuf_add(&path, args->base, args->baselen);
        strbuf_add(&path, base, baselen);
        strbuf_addstr(&path, filename);
+       if (S_ISDIR(mode) || S_ISGITLINK(mode))
+               strbuf_addch(&path, '/');
        path_without_prefix = path.buf + args->baselen;
 
        setup_archive_check(check);
@@ -130,7 +132,6 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        }
 
        if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
-               strbuf_addch(&path, '/');
                if (args->verbose)
                        fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
                err = write_entry(args, sha1, path.buf, path.len, mode);
diff --git a/attr.c b/attr.c
index 097ae87f3c2b4093fffe6586f036918367fa672e..8985c5c25b365276259838c1a50945b7e600dc31 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -564,18 +564,12 @@ static void bootstrap_attr_stack(void)
        attr_stack = elem;
 }
 
-static void prepare_attr_stack(const char *path)
+static void prepare_attr_stack(const char *path, int dirlen)
 {
        struct attr_stack *elem, *info;
-       int dirlen, len;
+       int len;
        const char *cp;
 
-       cp = strrchr(path, '/');
-       if (!cp)
-               dirlen = 0;
-       else
-               dirlen = cp - path;
-
        /*
         * At the bottom of the attribute stack is the built-in
         * set of attribute definitions, followed by the contents
@@ -668,6 +662,10 @@ static int path_matches(const char *pathname, int pathlen,
        const char *pattern = pat->pattern;
        int prefix = pat->nowildcardlen;
 
+       if ((pat->flags & EXC_FLAG_MUSTBEDIR) &&
+           ((!pathlen) || (pathname[pathlen-1] != '/')))
+               return 0;
+
        if (pat->flags & EXC_FLAG_NODIR) {
                return match_basename(basename,
                                      pathlen - (basename - pathname),
@@ -693,7 +691,7 @@ static int fill_one(const char *what, struct match_attr *a, int rem)
 
                if (*n == ATTR__UNKNOWN) {
                        debug_set(what,
-                                 a->is_macro ? a->u.attr->name : a->u.pattern,
+                                 a->is_macro ? a->u.attr->name : a->u.pat.pattern,
                                  attr, v);
                        *n = v;
                        rem--;
@@ -751,17 +749,26 @@ static int macroexpand_one(int attr_nr, int rem)
 static void collect_all_attrs(const char *path)
 {
        struct attr_stack *stk;
-       int i, pathlen, rem;
-       const char *basename;
+       int i, pathlen, rem, dirlen;
+       const char *basename, *cp, *last_slash = NULL;
 
-       prepare_attr_stack(path);
+       for (cp = path; *cp; cp++) {
+               if (*cp == '/' && cp[1])
+                       last_slash = cp;
+       }
+       pathlen = cp - path;
+       if (last_slash) {
+               basename = last_slash + 1;
+               dirlen = last_slash - path;
+       } else {
+               basename = path;
+               dirlen = 0;
+       }
+
+       prepare_attr_stack(path, dirlen);
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
 
-       basename = strrchr(path, '/');
-       basename = basename ? basename + 1 : path;
-
-       pathlen = strlen(path);
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
                rem = fill(path, pathlen, basename, stk, rem);
index 3faf9d6691413c006f4c82702aa5e0c5e4bc88a0..7e7bbd665a905b0fdf9ce5351f6f09dfd3dd7e8a 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -15,7 +15,8 @@ extern const char git_more_info_string[];
 extern void prune_packed_objects(int);
 
 struct fmt_merge_msg_opts {
-       unsigned add_title:1;
+       unsigned add_title:1,
+               credit_people:1;
        int shortlog_len;
 };
 
index e664100c7122d6c4116763716c2260756feffac2..632594768d9ee7d723a35377ab4cff9cf714a0d9 100644 (file)
@@ -16,7 +16,7 @@
 #include "bulk-checkin.h"
 
 static const char * const builtin_add_usage[] = {
-       N_("git add [options] [--] <filepattern>..."),
+       N_("git add [options] [--] <pathspec>..."),
        NULL
 };
 static int patch_interactive, add_interactive, edit_interactive;
index 156b3ce3b72f51013baacff0a8ffd37ac97e6158..080ce2ea3e4d6290e5db5567c0bdd217725a36c4 100644 (file)
@@ -1041,15 +1041,17 @@ static int gitdiff_renamedst(const char *line, struct patch *patch)
 
 static int gitdiff_similarity(const char *line, struct patch *patch)
 {
-       if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
-               patch->score = 0;
+       unsigned long val = strtoul(line, NULL, 10);
+       if (val <= 100)
+               patch->score = val;
        return 0;
 }
 
 static int gitdiff_dissimilarity(const char *line, struct patch *patch)
 {
-       if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
-               patch->score = 0;
+       unsigned long val = strtoul(line, NULL, 10);
+       if (val <= 100)
+               patch->score = val;
        return 0;
 }
 
@@ -2095,7 +2097,7 @@ static void update_pre_post_images(struct image *preimage,
                                   char *buf,
                                   size_t len, size_t postlen)
 {
-       int i, ctx;
+       int i, ctx, reduced;
        char *new, *old, *fixed;
        struct image fixed_preimage;
 
@@ -2105,8 +2107,10 @@ static void update_pre_post_images(struct image *preimage,
         * free "oldlines".
         */
        prepare_image(&fixed_preimage, buf, len, 1);
-       assert(fixed_preimage.nr == preimage->nr);
-       for (i = 0; i < preimage->nr; i++)
+       assert(postlen
+              ? fixed_preimage.nr == preimage->nr
+              : fixed_preimage.nr <= preimage->nr);
+       for (i = 0; i < fixed_preimage.nr; i++)
                fixed_preimage.line[i].flag = preimage->line[i].flag;
        free(preimage->line_allocated);
        *preimage = fixed_preimage;
@@ -2126,7 +2130,8 @@ static void update_pre_post_images(struct image *preimage,
        else
                new = old;
        fixed = preimage->buf;
-       for (i = ctx = 0; i < postimage->nr; i++) {
+
+       for (i = reduced = ctx = 0; i < postimage->nr; i++) {
                size_t len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
@@ -2145,8 +2150,15 @@ static void update_pre_post_images(struct image *preimage,
                        fixed += preimage->line[ctx].len;
                        ctx++;
                }
-               if (preimage->nr <= ctx)
-                       die(_("oops"));
+
+               /*
+                * preimage is expected to run out, if the caller
+                * fixed addition of trailing blank lines.
+                */
+               if (preimage->nr <= ctx) {
+                       reduced++;
+                       continue;
+               }
 
                /* and copy it in, while fixing the line length */
                len = preimage->line[ctx].len;
@@ -2159,6 +2171,7 @@ static void update_pre_post_images(struct image *preimage,
 
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
+       postimage->nr -= reduced;
 }
 
 static int match_fragment(struct image *img,
@@ -3598,7 +3611,6 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
         * worth showing the new sha1 prefix, but until then...
         */
        for (patch = list; patch; patch = patch->next) {
-               const unsigned char *sha1_ptr;
                unsigned char sha1[20];
                struct cache_entry *ce;
                const char *name;
@@ -3606,20 +3618,23 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
                name = patch->old_name ? patch->old_name : patch->new_name;
                if (0 < patch->is_new)
                        continue;
-               else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
-                       /* git diff has no index line for mode/type changes */
-                       if (!patch->lines_added && !patch->lines_deleted) {
-                               if (get_current_sha1(patch->old_name, sha1))
-                                       die("mode change for %s, which is not "
-                                               "in current HEAD", name);
-                               sha1_ptr = sha1;
-                       } else
-                               die("sha1 information is lacking or useless "
-                                       "(%s).", name);
-               else
-                       sha1_ptr = sha1;
 
-               ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
+               if (S_ISGITLINK(patch->old_mode)) {
+                       if (get_sha1_hex(patch->old_sha1_prefix, sha1))
+                               die("submoule change for %s without full index name",
+                                   name);
+               } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
+                       ; /* ok */
+               } else if (!patch->lines_added && !patch->lines_deleted) {
+                       /* mode-only change: update the current */
+                       if (get_current_sha1(patch->old_name, sha1))
+                               die("mode change for %s, which is not "
+                                   "in current HEAD", name);
+               } else
+                       die("sha1 information is lacking or useless "
+                           "(%s).", name);
+
+               ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);
                if (!ce)
                        die(_("make_cache_entry failed for path '%s'"), name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
index 1ec9c02612d0391984b484a5850f45c277a3e804..947c84be2daac5fd183c2d1fbd706e239eab63c5 100644 (file)
@@ -850,11 +850,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                const char *branch_name;
                struct strbuf branch_ref = STRBUF_INIT;
 
-               if (detached)
-                       die("Cannot give description to detached HEAD");
-               if (!argc)
+               if (!argc) {
+                       if (detached)
+                               die("Cannot give description to detached HEAD");
                        branch_name = head;
-               else if (argc == 1)
+               else if (argc == 1)
                        branch_name = argv[0];
                else
                        usage_with_options(builtin_branch_usage, options);
index 69c1cda9061f248479377d2841a1ddf703ea59ba..f4b760bf3dcb2371da6ae9d77f2f8fb1c0fa9eb9 100644 (file)
@@ -10,6 +10,7 @@
 #include "cache.h"
 #include "dir.h"
 #include "parse-options.h"
+#include "refs.h"
 #include "string-list.h"
 #include "quote.h"
 
@@ -20,6 +21,12 @@ static const char *const builtin_clean_usage[] = {
        NULL
 };
 
+static const char *msg_remove = N_("Removing %s\n");
+static const char *msg_would_remove = N_("Would remove %s\n");
+static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
+static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
+static const char *msg_warn_remove_failed = N_("failed to remove %s");
+
 static int git_clean_config(const char *var, const char *value, void *cb)
 {
        if (!strcmp(var, "clean.requireforce"))
@@ -34,11 +41,112 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
+static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
+               int dry_run, int quiet, int *dir_gone)
+{
+       DIR *dir;
+       struct strbuf quoted = STRBUF_INIT;
+       struct dirent *e;
+       int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
+       unsigned char submodule_head[20];
+       struct string_list dels = STRING_LIST_INIT_DUP;
+
+       *dir_gone = 1;
+
+       if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
+                       !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
+               if (!quiet) {
+                       quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+                       printf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
+                                       quoted.buf);
+               }
+
+               *dir_gone = 0;
+               return 0;
+       }
+
+       dir = opendir(path->buf);
+       if (!dir) {
+               /* an empty dir could be removed even if it is unreadble */
+               res = dry_run ? 0 : rmdir(path->buf);
+               if (res) {
+                       quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+                       warning(_(msg_warn_remove_failed), quoted.buf);
+                       *dir_gone = 0;
+               }
+               return res;
+       }
+
+       if (path->buf[original_len - 1] != '/')
+               strbuf_addch(path, '/');
+
+       len = path->len;
+       while ((e = readdir(dir)) != NULL) {
+               struct stat st;
+               if (is_dot_or_dotdot(e->d_name))
+                       continue;
+
+               strbuf_setlen(path, len);
+               strbuf_addstr(path, e->d_name);
+               if (lstat(path->buf, &st))
+                       ; /* fall thru */
+               else if (S_ISDIR(st.st_mode)) {
+                       if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
+                               ret = 1;
+                       if (gone) {
+                               quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+                               string_list_append(&dels, quoted.buf);
+                       } else
+                               *dir_gone = 0;
+                       continue;
+               } else {
+                       res = dry_run ? 0 : unlink(path->buf);
+                       if (!res) {
+                               quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+                               string_list_append(&dels, quoted.buf);
+                       } else {
+                               quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+                               warning(_(msg_warn_remove_failed), quoted.buf);
+                               *dir_gone = 0;
+                               ret = 1;
+                       }
+                       continue;
+               }
+
+               /* path too long, stat fails, or non-directory still exists */
+               *dir_gone = 0;
+               ret = 1;
+               break;
+       }
+       closedir(dir);
+
+       strbuf_setlen(path, original_len);
+
+       if (*dir_gone) {
+               res = dry_run ? 0 : rmdir(path->buf);
+               if (!res)
+                       *dir_gone = 1;
+               else {
+                       quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
+                       warning(_(msg_warn_remove_failed), quoted.buf);
+                       *dir_gone = 0;
+                       ret = 1;
+               }
+       }
+
+       if (!*dir_gone && !quiet) {
+               for (i = 0; i < dels.nr; i++)
+                       printf(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string);
+       }
+       string_list_clear(&dels, 0);
+       return ret;
+}
+
 int cmd_clean(int argc, const char **argv, const char *prefix)
 {
-       int i;
-       int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
-       int ignored_only = 0, config_set = 0, errors = 0;
+       int i, res;
+       int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
+       int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
        int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
        struct strbuf directory = STRBUF_INIT;
        struct dir_struct dir;
@@ -49,7 +157,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        char *seen = NULL;
        struct option options[] = {
                OPT__QUIET(&quiet, N_("do not print names of files removed")),
-               OPT__DRY_RUN(&show_only, N_("dry run")),
+               OPT__DRY_RUN(&dry_run, N_("dry run")),
                OPT__FORCE(&force, N_("force")),
                OPT_BOOLEAN('d', NULL, &remove_directories,
                                N_("remove whole directories")),
@@ -77,7 +185,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        if (ignored && ignored_only)
                die(_("-x and -X cannot be used together"));
 
-       if (!show_only && !force) {
+       if (!dry_run && !force) {
                if (config_set)
                        die(_("clean.requireForce set to true and neither -n nor -f given; "
                                  "refusing to clean"));
@@ -149,38 +257,26 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 
                if (S_ISDIR(st.st_mode)) {
                        strbuf_addstr(&directory, ent->name);
-                       qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
-                       if (show_only && (remove_directories ||
-                           (matches == MATCHED_EXACTLY))) {
-                               printf(_("Would remove %s\n"), qname);
-                       } else if (remove_directories ||
-                                  (matches == MATCHED_EXACTLY)) {
-                               if (!quiet)
-                                       printf(_("Removing %s\n"), qname);
-                               if (remove_dir_recursively(&directory,
-                                                          rm_flags) != 0) {
-                                       warning(_("failed to remove %s"), qname);
+                       if (remove_directories || (matches == MATCHED_EXACTLY)) {
+                               if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
                                        errors++;
+                               if (gone && !quiet) {
+                                       qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
+                                       printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
                                }
-                       } else if (show_only) {
-                               printf(_("Would not remove %s\n"), qname);
-                       } else {
-                               printf(_("Not removing %s\n"), qname);
                        }
                        strbuf_reset(&directory);
                } else {
                        if (pathspec && !matches)
                                continue;
-                       qname = quote_path_relative(ent->name, -1, &buf, prefix);
-                       if (show_only) {
-                               printf(_("Would remove %s\n"), qname);
-                               continue;
-                       } else if (!quiet) {
-                               printf(_("Removing %s\n"), qname);
-                       }
-                       if (unlink(ent->name) != 0) {
-                               warning(_("failed to remove %s"), qname);
+                       res = dry_run ? 0 : unlink(ent->name);
+                       if (res) {
+                               qname = quote_path_relative(ent->name, -1, &buf, prefix);
+                               warning(_(msg_warn_remove_failed), qname);
                                errors++;
+                       } else if (!quiet) {
+                               qname = quote_path_relative(ent->name, -1, &buf, prefix);
+                               printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
                        }
                }
        }
index ec2f75b4f3b9d9acfb8aa6b423f3b0fc7fbbafdf..36ec99db3f5a7dbd59705aa68bcd592c08c773cd 100644 (file)
@@ -704,6 +704,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                if (option_origin)
                        die(_("--bare and --origin %s options are incompatible."),
                            option_origin);
+               if (real_git_dir)
+                       die(_("--bare and --separate-git-dir are incompatible."));
                option_no_checkout = 1;
        }
 
@@ -771,8 +773,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                die(_("could not create leading directories of '%s'"), git_dir);
 
        set_git_dir_init(git_dir, real_git_dir, 0);
-       if (real_git_dir)
+       if (real_git_dir) {
                git_dir = real_git_dir;
+               junk_git_dir = real_git_dir;
+       }
 
        if (0 <= option_verbosity) {
                if (option_bare)
index d6dd3df8b1e1f449e7781bdb033f5cfa11753436..96684108e7437537536c42fafa7a84ddef848520 100644 (file)
 #include "sequencer.h"
 
 static const char * const builtin_commit_usage[] = {
-       N_("git commit [options] [--] <filepattern>..."),
+       N_("git commit [options] [--] <pathspec>..."),
        NULL
 };
 
 static const char * const builtin_status_usage[] = {
-       N_("git status [options] [--] <filepattern>..."),
+       N_("git status [options] [--] <pathspec>..."),
        NULL
 };
 
index e2e27b2c404a1c451a20e396a7aa03dece722dad..d9af43c257150c957bf3bc3c3b7a7e43e370174c 100644 (file)
@@ -232,8 +232,9 @@ static void record_person(int which, struct string_list *people,
 {
        char *name_buf, *name, *name_end;
        struct string_list_item *elem;
-       const char *field = (which == 'a') ? "\nauthor " : "\ncommitter ";
+       const char *field;
 
+       field = (which == 'a') ? "\nauthor " : "\ncommitter ";
        name = strstr(commit->buffer, field);
        if (!name)
                return;
@@ -323,7 +324,8 @@ static void add_people_info(struct strbuf *out,
 static void shortlog(const char *name,
                     struct origin_data *origin_data,
                     struct commit *head,
-                    struct rev_info *rev, int limit,
+                    struct rev_info *rev,
+                    struct fmt_merge_msg_opts *opts,
                     struct strbuf *out)
 {
        int i, count = 0;
@@ -335,6 +337,7 @@ static void shortlog(const char *name,
        int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
        struct strbuf sb = STRBUF_INIT;
        const unsigned char *sha1 = origin_data->sha1;
+       int limit = opts->shortlog_len;
 
        branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
        if (!branch || branch->type != OBJ_COMMIT)
@@ -351,13 +354,15 @@ static void shortlog(const char *name,
 
                if (commit->parents && commit->parents->next) {
                        /* do not list a merge but count committer */
-                       record_person('c', &committers, commit);
+                       if (opts->credit_people)
+                               record_person('c', &committers, commit);
                        continue;
                }
-               if (!count)
+               if (!count && opts->credit_people)
                        /* the 'tip' committer */
                        record_person('c', &committers, commit);
-               record_person('a', &authors, commit);
+               if (opts->credit_people)
+                       record_person('a', &authors, commit);
                count++;
                if (subjects.nr > limit)
                        continue;
@@ -372,7 +377,8 @@ static void shortlog(const char *name,
                        string_list_append(&subjects, strbuf_detach(&sb, NULL));
        }
 
-       add_people_info(out, &authors, &committers);
+       if (opts->credit_people)
+               add_people_info(out, &authors, &committers);
        if (count > limit)
                strbuf_addf(out, "\n* %s: (%d commits)\n", name, count);
        else
@@ -635,7 +641,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                for (i = 0; i < origins.nr; i++)
                        shortlog(origins.items[i].string,
                                 origins.items[i].util,
-                                head, &rev, opts->shortlog_len, out);
+                                head, &rev, opts, out);
        }
 
        strbuf_complete_line(out);
@@ -690,6 +696,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 
        memset(&opts, 0, sizeof(opts));
        opts.add_title = !message;
+       opts.credit_people = 1;
        opts.shortlog_len = shortlog_len;
 
        ret = fmt_merge_msg(&input, &output, &opts);
index bd86253d835fce671ed19676e5efeb59a6fc261d..6067a6134b58f2464b243f47112226a0a013f5c4 100644 (file)
@@ -6,7 +6,6 @@
 #include "cache.h"
 #include "builtin.h"
 #include "exec_cmd.h"
-#include "common-cmds.h"
 #include "parse-options.h"
 #include "run-command.h"
 #include "column.h"
@@ -287,23 +286,6 @@ static int git_help_config(const char *var, const char *value, void *cb)
 
 static struct cmdnames main_cmds, other_cmds;
 
-void list_common_cmds_help(void)
-{
-       int i, longest = 0;
-
-       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
-               if (longest < strlen(common_cmds[i].name))
-                       longest = strlen(common_cmds[i].name);
-       }
-
-       puts(_("The most commonly used git commands are:"));
-       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
-               printf("   %s   ", common_cmds[i].name);
-               mput_char(' ', longest - strlen(common_cmds[i].name));
-               puts(_(common_cmds[i].help));
-       }
-}
-
 static int is_git_command(const char *s)
 {
        return is_in_cmdlist(&main_cmds, s) ||
index 23388325879c5a52a4a8c25f254aafe23573e820..be5e514324aba1d50d8afe653dd72ccc5db060d8 100644 (file)
@@ -42,7 +42,7 @@ static int merge_entry(int pos, const char *path)
        return found;
 }
 
-static void merge_file(const char *path)
+static void merge_one_path(const char *path)
 {
        int pos = cache_name_pos(path, strlen(path));
 
@@ -102,7 +102,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
                        }
                        die("git merge-index: unknown option %s", arg);
                }
-               merge_file(arg);
+               merge_one_path(arg);
        }
        if (err && !quiet)
                die("merge program failed");
index 897a563bc6662e108c29656d633b7400384154f9..e0d0b7d28b9e1e67fe6ea6521a683df89f5c9416 100644 (file)
@@ -3,17 +3,15 @@
 #include "xdiff-interface.h"
 #include "blob.h"
 #include "exec_cmd.h"
-#include "merge-file.h"
+#include "merge-blobs.h"
 
 static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
-static int resolve_directories = 1;
 
 struct merge_list {
        struct merge_list *next;
        struct merge_list *link;        /* other stages for this object */
 
-       unsigned int stage : 2,
-                    flags : 30;
+       unsigned int stage : 2;
        unsigned int mode;
        const char *path;
        struct blob *blob;
@@ -27,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry)
        merge_result_end = &entry->next;
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base);
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
 
 static const char *explanation(struct merge_list *entry)
 {
@@ -76,7 +74,7 @@ static void *result(struct merge_list *entry, unsigned long *size)
        their = NULL;
        if (entry)
                their = entry->blob;
-       return merge_file(path, base, our, their, size);
+       return merge_blobs(path, base, our, their, size);
 }
 
 static void *origin(struct merge_list *entry, unsigned long *size)
@@ -174,17 +172,17 @@ static char *traverse_path(const struct traverse_info *info, const struct name_e
        return make_traverse_path(path, info, n);
 }
 
-static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
+static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
 {
        struct merge_list *orig, *final;
        const char *path;
 
-       /* If it's already branch1, don't bother showing it */
-       if (!branch1)
+       /* If it's already ours, don't bother showing it */
+       if (!ours)
                return;
 
        path = traverse_path(info, result);
-       orig = create_entry(2, branch1->mode, branch1->sha1, path);
+       orig = create_entry(2, ours->mode, ours->sha1, path);
        final = create_entry(0, result->mode, result->sha1, path);
 
        final->link = orig;
@@ -192,34 +190,35 @@ static void resolve(const struct traverse_info *info, struct name_entry *branch1
        add_merge_entry(final);
 }
 
-static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
+static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
+                                int df_conflict)
 {
        char *newbase;
        struct name_entry *p;
        struct tree_desc t[3];
        void *buf0, *buf1, *buf2;
 
-       if (!resolve_directories)
-               return 0;
-       p = n;
-       if (!p->mode) {
-               p++;
-               if (!p->mode)
-                       p++;
+       for (p = n; p < n + 3; p++) {
+               if (p->mode && S_ISDIR(p->mode))
+                       break;
        }
-       if (!S_ISDIR(p->mode))
-               return 0;
+       if (n + 3 <= p)
+               return; /* there is no tree here */
+
        newbase = traverse_path(info, p);
-       buf0 = fill_tree_descriptor(t+0, n[0].sha1);
-       buf1 = fill_tree_descriptor(t+1, n[1].sha1);
-       buf2 = fill_tree_descriptor(t+2, n[2].sha1);
-       merge_trees(t, newbase);
+
+#define ENTRY_SHA1(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->sha1 : NULL)
+       buf0 = fill_tree_descriptor(t+0, ENTRY_SHA1(n + 0));
+       buf1 = fill_tree_descriptor(t+1, ENTRY_SHA1(n + 1));
+       buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
+#undef ENTRY_SHA1
+
+       merge_trees_recursive(t, newbase, df_conflict);
 
        free(buf0);
        free(buf1);
        free(buf2);
        free(newbase);
-       return 1;
 }
 
 
@@ -242,18 +241,26 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
 static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 {
        struct merge_list *entry = NULL;
+       int i;
+       unsigned dirmask = 0, mask = 0;
+
+       for (i = 0; i < 3; i++) {
+               mask |= (1 << 1);
+               if (n[i].mode && S_ISDIR(n[i].mode))
+                       dirmask |= (1 << i);
+       }
 
-       if (unresolved_directory(info, n))
+       unresolved_directory(info, n, dirmask && (dirmask != mask));
+
+       if (dirmask == mask)
                return;
 
-       /*
-        * Do them in reverse order so that the resulting link
-        * list has the stages in order - link_entry adds new
-        * links at the front.
-        */
-       entry = link_entry(3, info, n + 2, entry);
-       entry = link_entry(2, info, n + 1, entry);
-       entry = link_entry(1, info, n + 0, entry);
+       if (n[2].mode && !S_ISDIR(n[2].mode))
+               entry = link_entry(3, info, n + 2, entry);
+       if (n[1].mode && !S_ISDIR(n[1].mode))
+               entry = link_entry(2, info, n + 1, entry);
+       if (n[0].mode && !S_ISDIR(n[0].mode))
+               entry = link_entry(1, info, n + 0, entry);
 
        add_merge_entry(entry);
 }
@@ -292,20 +299,29 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
        /* Same in both? */
        if (same_entry(entry+1, entry+2)) {
                if (entry[0].sha1) {
+                       /* Modified identically */
                        resolve(info, NULL, entry+1);
                        return mask;
                }
+               /* "Both added the same" is left unresolved */
        }
 
        if (same_entry(entry+0, entry+1)) {
                if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
+                       /* We did not touch, they modified -- take theirs */
                        resolve(info, entry+1, entry+2);
                        return mask;
                }
+               /*
+                * If we did not touch a directory but they made it
+                * into a file, we fall through and unresolved()
+                * recurses down.  Likewise for the opposite case.
+                */
        }
 
        if (same_entry(entry+0, entry+2)) {
                if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
+                       /* We modified, they did not touch -- take ours */
                        resolve(info, NULL, entry+1);
                        return mask;
                }
@@ -315,15 +331,21 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
        return mask;
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base)
+static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
 {
        struct traverse_info info;
 
        setup_traverse_info(&info, base);
+       info.data = &df_conflict;
        info.fn = threeway_callback;
        traverse_trees(3, t, &info);
 }
 
+static void merge_trees(struct tree_desc t[3], const char *base)
+{
+       merge_trees_recursive(t, base, 0);
+}
+
 static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
 {
        unsigned char sha1[20];
index a96e8eac19911c710f0f6870a53bda480b09747b..9307e9c726587461d002530938dbf2c0d74d55a1 100644 (file)
@@ -800,8 +800,9 @@ static void prepare_to_commit(struct commit_list *remoteheads)
        if (0 < option_edit)
                strbuf_add_lines(&msg, "# ", comment, strlen(comment));
        write_merge_msg(&msg);
-       run_hook(get_index_file(), "prepare-commit-msg",
-                git_path("MERGE_MSG"), "merge", NULL, NULL);
+       if (run_hook(get_index_file(), "prepare-commit-msg",
+                    git_path("MERGE_MSG"), "merge", NULL, NULL))
+               abort_commit(remoteheads, NULL);
        if (0 < option_edit) {
                if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
                        abort_commit(remoteheads, NULL);
@@ -1221,6 +1222,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        memset(&opts, 0, sizeof(opts));
                        opts.add_title = !have_message;
                        opts.shortlog_len = shortlog_len;
+                       opts.credit_people = (0 < option_edit);
 
                        fmt_merge_msg(&merge_names, &merge_msg, &opts);
                        if (merge_msg.len)
index b316cf37ca768f1502c5d0cfa64372a9b322a572..83605143ac0cea68b421dd9a3c056d3a27f66be9 100644 (file)
@@ -306,9 +306,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
                                     const struct shortlog *log)
 {
-       int col = strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
-       if (col != log->wrap)
-               strbuf_addch(sb, '\n');
+       strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
+       strbuf_addch(sb, '\n');
 }
 
 void shortlog_output(struct shortlog *log)
index 28ed6574a2faf3151056aa20e681e06a157e4a2d..37e4d008b59420338ce97f1b2cf2eb660dab8a34 100644 (file)
@@ -166,12 +166,8 @@ static int verify_cache(struct cache_entry **cache,
                                fprintf(stderr, "...\n");
                                break;
                        }
-                       if (ce_stage(ce))
-                               fprintf(stderr, "%s: unmerged (%s)\n",
-                                       ce->name, sha1_to_hex(ce->sha1));
-                       else
-                               fprintf(stderr, "%s: not added yet\n",
-                                       ce->name);
+                       fprintf(stderr, "%s: unmerged (%s)\n",
+                               ce->name, sha1_to_hex(ce->sha1));
                }
        }
        if (funny)
@@ -242,13 +238,17 @@ static int update_one(struct cache_tree *it,
                      int entries,
                      const char *base,
                      int baselen,
+                     int *skip_count,
                      int flags)
 {
        struct strbuf buffer;
        int missing_ok = flags & WRITE_TREE_MISSING_OK;
        int dryrun = flags & WRITE_TREE_DRY_RUN;
+       int to_invalidate = 0;
        int i;
 
+       *skip_count = 0;
+
        if (0 <= it->entry_count && has_sha1_file(it->sha1))
                return it->entry_count;
 
@@ -263,11 +263,12 @@ static int update_one(struct cache_tree *it,
        /*
         * Find the subtrees and update them.
         */
-       for (i = 0; i < entries; i++) {
+       i = 0;
+       while (i < entries) {
                struct cache_entry *ce = cache[i];
                struct cache_tree_sub *sub;
                const char *path, *slash;
-               int pathlen, sublen, subcnt;
+               int pathlen, sublen, subcnt, subskip;
 
                path = ce->name;
                pathlen = ce_namelen(ce);
@@ -275,8 +276,10 @@ static int update_one(struct cache_tree *it,
                        break; /* at the end of this level */
 
                slash = strchr(path + baselen, '/');
-               if (!slash)
+               if (!slash) {
+                       i++;
                        continue;
+               }
                /*
                 * a/bbb/c (base = a/, slash = /c)
                 * ==>
@@ -290,10 +293,13 @@ static int update_one(struct cache_tree *it,
                                    cache + i, entries - i,
                                    path,
                                    baselen + sublen + 1,
+                                   &subskip,
                                    flags);
                if (subcnt < 0)
                        return subcnt;
-               i += subcnt - 1;
+               i += subcnt;
+               sub->count = subcnt; /* to be used in the next loop */
+               *skip_count += subskip;
                sub->used = 1;
        }
 
@@ -304,7 +310,8 @@ static int update_one(struct cache_tree *it,
         */
        strbuf_init(&buffer, 8192);
 
-       for (i = 0; i < entries; i++) {
+       i = 0;
+       while (i < entries) {
                struct cache_entry *ce = cache[i];
                struct cache_tree_sub *sub;
                const char *path, *slash;
@@ -324,14 +331,17 @@ static int update_one(struct cache_tree *it,
                        if (!sub)
                                die("cache-tree.c: '%.*s' in '%s' not found",
                                    entlen, path + baselen, path);
-                       i += sub->cache_tree->entry_count - 1;
+                       i += sub->count;
                        sha1 = sub->cache_tree->sha1;
                        mode = S_IFDIR;
+                       if (sub->cache_tree->entry_count < 0)
+                               to_invalidate = 1;
                }
                else {
                        sha1 = ce->sha1;
                        mode = ce->ce_mode;
                        entlen = pathlen - baselen;
+                       i++;
                }
                if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
                        strbuf_release(&buffer);
@@ -339,8 +349,25 @@ static int update_one(struct cache_tree *it,
                                mode, sha1_to_hex(sha1), entlen+baselen, path);
                }
 
-               if (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD))
-                       continue; /* entry being removed or placeholder */
+               /*
+                * CE_REMOVE entries are removed before the index is
+                * written to disk. Skip them to remain consistent
+                * with the future on-disk index.
+                */
+               if (ce->ce_flags & CE_REMOVE) {
+                       *skip_count = *skip_count + 1;
+                       continue;
+               }
+
+               /*
+                * CE_INTENT_TO_ADD entries exist on on-disk index but
+                * they are not part of generated trees. Invalidate up
+                * to root to force cache-tree users to read elsewhere.
+                */
+               if (ce->ce_flags & CE_INTENT_TO_ADD) {
+                       to_invalidate = 1;
+                       continue;
+               }
 
                strbuf_grow(&buffer, entlen + 100);
                strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
@@ -360,7 +387,7 @@ static int update_one(struct cache_tree *it,
        }
 
        strbuf_release(&buffer);
-       it->entry_count = i;
+       it->entry_count = to_invalidate ? -1 : i - *skip_count;
 #if DEBUG
        fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
                it->entry_count, it->subtree_nr,
@@ -374,11 +401,11 @@ int cache_tree_update(struct cache_tree *it,
                      int entries,
                      int flags)
 {
-       int i;
+       int i, skip;
        i = verify_cache(cache, entries, flags);
        if (i)
                return i;
-       i = update_one(it, cache, entries, "", 0, flags);
+       i = update_one(it, cache, entries, "", 0, &skip, flags);
        if (i < 0)
                return i;
        return 0;
index d8cb2e9e39d2be9c4dad67db44a464c2a1004d2f..55d0f59f2b7a42b40fe4be32297b56656206983d 100644 (file)
@@ -7,6 +7,7 @@
 struct cache_tree;
 struct cache_tree_sub {
        struct cache_tree *cache_tree;
+       int count;              /* internally used by update_one() */
        int namelen;
        int used;
        char name[FLEX_ARRAY];
diff --git a/cache.h b/cache.h
index 18fdd18f3674b1d7c62de65509bdb7bc57743395..2b192d24ac63181b0bba08805c09f004af8ef1dc 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -714,10 +714,11 @@ static inline int is_absolute_path(const char *path)
 }
 int is_directory(const char *);
 const char *real_path(const char *path);
+const char *real_path_if_valid(const char *path);
 const char *absolute_path(const char *path);
 const char *relative_path(const char *abs, const char *base);
 int normalize_path_copy(char *dst, const char *src);
-int longest_ancestor_length(const char *path, const char *prefix_list);
+int longest_ancestor_length(const char *path, struct string_list *prefixes);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
 int offset_1st_component(const char *path);
index bb1cc96c4e73c90ee327858aa3b36cf2bfe043a4..7f6187f9cd2fc44540cddbcf4bb853231c57397c 100644 (file)
@@ -982,14 +982,10 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        free(sline);
 }
 
-#define COLONS "::::::::::::::::::::::::::::::::"
-
 static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
-       int i, offset;
-       const char *prefix;
-       int line_termination, inter_name_termination;
+       int line_termination, inter_name_termination, i;
 
        line_termination = opt->line_termination;
        inter_name_termination = '\t';
@@ -1000,17 +996,14 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
                show_log(rev);
 
        if (opt->output_format & DIFF_FORMAT_RAW) {
-               offset = strlen(COLONS) - num_parent;
-               if (offset < 0)
-                       offset = 0;
-               prefix = COLONS + offset;
+               /* As many colons as there are parents */
+               for (i = 0; i < num_parent; i++)
+                       putchar(':');
 
                /* Show the modes */
-               for (i = 0; i < num_parent; i++) {
-                       printf("%s%06o", prefix, p->parent[i].mode);
-                       prefix = " ";
-               }
-               printf("%s%06o", prefix, p->mode);
+               for (i = 0; i < num_parent; i++)
+                       printf("%06o ", p->parent[i].mode);
+               printf("%06o", p->mode);
 
                /* Show sha1's */
                for (i = 0; i < num_parent; i++)
index 0ff1d273a5839d15a908a4ed90b56d59b151e6e0..b8b7dc254373fb0f7b2a7b16163fa72e1e8c5f7b 100644 (file)
@@ -135,9 +135,9 @@ extern int errno;
 
 # if !defined HAVE___STRCHRNUL && !defined _LIBC
 static char *
-__strchrnul (s, c)
-     const char *s;
-     int c;
+__strchrnul (const char *s, int c)
+
+
 {
   char *result = strchr (s, c);
   if (result == NULL)
@@ -159,11 +159,11 @@ static int internal_fnmatch __P ((const char *pattern, const char *string,
      internal_function;
 static int
 internal_function
-internal_fnmatch (pattern, string, no_leading_period, flags)
-     const char *pattern;
-     const char *string;
-     int no_leading_period;
-     int flags;
+internal_fnmatch (const char *pattern, const char *string, int no_leading_period, int flags)
+
+
+
+
 {
   register const char *p = pattern, *n = string;
   register unsigned char c;
@@ -481,10 +481,10 @@ internal_fnmatch (pattern, string, no_leading_period, flags)
 
 
 int
-fnmatch (pattern, string, flags)
-     const char *pattern;
-     const char *string;
-     int flags;
+fnmatch (const char *pattern, const char *string, int flags)
+
+
+
 {
   return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
 }
index d9a17a8057c5740edea3d7888c4607e63af9eddd..91c4e7f27b4063c7ceffeeb1cd43530ce18cf096 100644 (file)
@@ -603,7 +603,10 @@ static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, si
                }
                /* We really want to make sure this goes into memory now but we
                have to be careful of breaking aliasing rules, so write it twice */
-               *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp;
+               {
+                       volatile struct malloc_state **_m=(volatile struct malloc_state **) &p->m[end];
+                       *_m=(p->m[end]=temp);
+               }
                ACQUIRE_LOCK(&p->m[end]->mutex);
                /*printf("Created mspace idx %d\n", end);*/
                RELEASE_LOCK(&p->mutex);
index fb3f8681eed21ee81cfe36296c438ed135b98485..b5696354fa0e2b176c6d99ae0f34ba1bf1ecc5f7 100644 (file)
--- a/config.c
+++ b/config.c
@@ -58,7 +58,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
                path = buf.buf;
        }
 
-       if (!access_or_warn(path, R_OK)) {
+       if (!access_or_die(path, R_OK)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
                            cf && cf->name ? cf->name : "the command line");
@@ -938,23 +938,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
        home_config_paths(&user_config, &xdg_config, "config");
 
-       if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
+       if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
                found += 1;
        }
 
-       if (xdg_config && !access_or_warn(xdg_config, R_OK)) {
+       if (xdg_config && !access_or_die(xdg_config, R_OK)) {
                ret += git_config_from_file(fn, xdg_config, data);
                found += 1;
        }
 
-       if (user_config && !access_or_warn(user_config, R_OK)) {
+       if (user_config && !access_or_die(user_config, R_OK)) {
                ret += git_config_from_file(fn, user_config, data);
                found += 1;
        }
 
-       if (repo_config && !access_or_warn(repo_config, R_OK)) {
+       if (repo_config && !access_or_die(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
index ad215cc4a10ed95804e7cec929f003c985d25a3d..41ac9a5e2d29b5f797a03052c3a17a8b42dac093 100644 (file)
@@ -1021,7 +1021,17 @@ if test -n "$USER_NOPTHREAD"; then
 # -D_REENTRANT' or some such.
 elif test -z "$PTHREAD_CFLAGS"; then
   threads_found=no
-  for opt in -mt -pthread -lpthread; do
+  # Attempt to compile and link some code using pthreads to determine
+  # required linker flags. The order is somewhat important here: We
+  # first try it without any extra flags, to catch systems where
+  # pthreads are part of the C library, then go on testing various other
+  # flags. We do so to avoid false positives. For example, on Mac OS X
+  # pthreads are part of the C library; moreover, the compiler allows us
+  # to add "-mt" to the CFLAGS (although it will do nothing except
+  # trigger a warning about an unused flag). Hence if we checked for
+  # "-mt" before "" we would end up picking it. But unfortunately this
+  # would then trigger compiler warnings on every single file we compile.
+  for opt in "" -mt -pthread -lpthread; do
      old_CFLAGS="$CFLAGS"
      CFLAGS="$opt $CFLAGS"
      AC_MSG_CHECKING([for POSIX Threads with '$opt'])
index 0b77eb1fa4074fb8ed5ef4cd4c37513f49804e7e..2186b4b77e1bc415e2d92ff6b68b1af8cc170a7e 100644 (file)
@@ -397,7 +397,7 @@ __git_complete_revlist_file ()
                *)   pfx="$ref:$pfx" ;;
                esac
 
-               __gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
+               __gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" 2>/dev/null \
                                | sed '/^100... blob /{
                                           s,^.*        ,,
                                           s,$, ,
@@ -531,10 +531,19 @@ __git_complete_strategy ()
        return 1
 }
 
+__git_commands () {
+       if test -n "${GIT_TESTING_COMMAND_COMPLETION:-}"
+       then
+               printf "%s" "${GIT_TESTING_COMMAND_COMPLETION}"
+       else
+               git help -a|egrep '^  [a-zA-Z0-9]'
+       fi
+}
+
 __git_list_all_commands ()
 {
        local i IFS=" "$'\n'
-       for i in $(git help -a|egrep '^  [a-zA-Z0-9]')
+       for i in $(__git_commands)
        do
                case $i in
                *--*)             : helper pattern;;
@@ -971,6 +980,13 @@ _git_commit ()
 {
        __git_has_doubledash && return
 
+       case "$prev" in
+       -c|-C)
+               __gitcomp_nl "$(__git_refs)" "" "${cur}"
+               return
+               ;;
+       esac
+
        case "$cur" in
        --cleanup=*)
                __gitcomp "default strip verbatim whitespace
@@ -2424,7 +2440,7 @@ if [[ -n ${ZSH_VERSION-} ]]; then
                                --*=*|*.) ;;
                                *) c="$c " ;;
                                esac
-                               array+=("$c")
+                               array[$#array+1]="$c"
                        done
                        compset -P '*[=:]'
                        compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
index 8aafb63315c52a08e6f581e0ef13aa9c239b03a8..3e3889f2b4fd3acb441e56284750cb22fef80547 100644 (file)
@@ -13,6 +13,7 @@
 #
 # To use this completion script:
 #
+#    0) You need tcsh 6.16.00 or newer.
 #    1) Copy both this file and the bash completion script to ${HOME}.
 #       You _must_ use the name ${HOME}/.git-completion.bash for the
 #       bash script.
 #        set autolist=ambiguous
 #       It will tell tcsh to list the possible completion choices.
 
+set __git_tcsh_completion_version = `\echo ${tcsh} | \sed 's/\./ /g'`
+if ( ${__git_tcsh_completion_version[1]} < 6 || \
+     ( ${__git_tcsh_completion_version[1]} == 6 && \
+       ${__git_tcsh_completion_version[2]} < 16 ) ) then
+       echo "git-completion.tcsh: Your version of tcsh is too old, you need version 6.16.00 or newer.  Git completion will not work."
+       exit
+endif
+unset __git_tcsh_completion_version
+
 set __git_tcsh_completion_original_script = ${HOME}/.git-completion.bash
 set __git_tcsh_completion_script = ${HOME}/.git-completion.tcsh.bash
 
@@ -64,9 +74,7 @@ fi
 _\${1}
 
 IFS=\$'\n'
-if [ \${#COMPREPLY[*]} -gt 0 ]; then
-       echo "\${COMPREPLY[*]}" | sort | uniq
-else
+if [ \${#COMPREPLY[*]} -eq 0 ]; then
        # No completions suggested.  In this case, we want tcsh to perform
        # standard file completion.  However, there does not seem to be way
        # to tell tcsh to do that.  To help the user, we try to simulate
@@ -85,19 +93,20 @@ else
                # We don't support ~ expansion: too tricky.
                if [ "\${TO_COMPLETE:0:1}" != "~" ]; then
                        # Use ls so as to add the '/' at the end of directories.
-                       RESULT=(\`ls -dp \${TO_COMPLETE}* 2> /dev/null\`)
-                       echo \${RESULT[*]}
-
-                       # If there is a single completion and it is a directory,
-                       # we output it a second time to trick tcsh into not adding a space
-                       # after it.
-                       if [ \${#RESULT[*]} -eq 1 ] && [ "\${RESULT[0]: -1}" == "/" ]; then
-                               echo \${RESULT[*]}
-                       fi
+                       COMPREPLY=(\`ls -dp \${TO_COMPLETE}* 2> /dev/null\`)
                fi
        fi
 fi
 
+# tcsh does not automatically remove duplicates, so we do it ourselves
+echo "\${COMPREPLY[*]}" | sort | uniq
+
+# If there is a single completion and it is a directory, we output it
+# a second time to trick tcsh into not adding a space after it.
+if [ \${#COMPREPLY[*]} -eq 1 ] && [ "\${COMPREPLY[0]: -1}" == "/" ]; then
+       echo "\${COMPREPLY[*]}"
+fi
+
 EOF
 
 # Don't need this variable anymore, so don't pollute the users environment
index 9b074e148d980e5b96819345be23f9b614db849d..9bef0531c5d9358e906bb7872f0775e165caac2c 100644 (file)
@@ -24,6 +24,8 @@
 #        will show username, at-sign, host, colon, cwd, then
 #        various status string, followed by dollar and SP, as
 #        your prompt.
+#        Optionally, you can supply a third argument with a printf
+#        format string to finetune the output of the branch status
 #
 # The argument to __git_ps1 will be displayed only if you are currently
 # in a git repository.  The %s token will be the name of the current
@@ -222,10 +224,12 @@ __git_ps1_show_upstream ()
 # when called from PS1 using command substitution
 # in this mode it prints text to add to bash PS1 prompt (includes branch name)
 #
-# __git_ps1 requires 2 arguments when called from PROMPT_COMMAND (pc)
+# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc)
 # in that case it _sets_ PS1. The arguments are parts of a PS1 string.
-# when both arguments are given, the first is prepended and the second appended
+# when two arguments are given, the first is prepended and the second appended
 # to the state string when assigned to PS1.
+# The optional third parameter will be used as printf format string to further
+# customize the output of the git-status string.
 # In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
 __git_ps1 ()
 {
@@ -236,9 +240,10 @@ __git_ps1 ()
        local printf_format=' (%s)'
 
        case "$#" in
-               2)      pcmode=yes
+               2|3)    pcmode=yes
                        ps1pc_start="$1"
                        ps1pc_end="$2"
+                       printf_format="${3:-$printf_format}"
                ;;
                0|1)    printf_format="${1:-$printf_format}"
                ;;
@@ -339,6 +344,7 @@ __git_ps1 ()
 
                local f="$w$i$s$u"
                if [ $pcmode = yes ]; then
+                       local gitstring=
                        if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
                                local c_red='\e[31m'
                                local c_green='\e[32m'
@@ -356,29 +362,31 @@ __git_ps1 ()
                                        branch_color="$bad_color"
                                fi
 
-                               # Setting PS1 directly with \[ and \] around colors
+                               # Setting gitstring directly with \[ and \] around colors
                                # is necessary to prevent wrapping issues!
-                               PS1="$ps1pc_start (\[$branch_color\]$branchstring\[$c_clear\]"
+                               gitstring="\[$branch_color\]$branchstring\[$c_clear\]"
 
                                if [ -n "$w$i$s$u$r$p" ]; then
-                                       PS1="$PS1 "
+                                       gitstring="$gitstring "
                                fi
                                if [ "$w" = "*" ]; then
-                                       PS1="$PS1\[$bad_color\]$w"
+                                       gitstring="$gitstring\[$bad_color\]$w"
                                fi
                                if [ -n "$i" ]; then
-                                       PS1="$PS1\[$ok_color\]$i"
+                                       gitstring="$gitstring\[$ok_color\]$i"
                                fi
                                if [ -n "$s" ]; then
-                                       PS1="$PS1\[$flags_color\]$s"
+                                       gitstring="$gitstring\[$flags_color\]$s"
                                fi
                                if [ -n "$u" ]; then
-                                       PS1="$PS1\[$bad_color\]$u"
+                                       gitstring="$gitstring\[$bad_color\]$u"
                                fi
-                               PS1="$PS1\[$c_clear\]$r$p)$ps1pc_end"
+                               gitstring="$gitstring\[$c_clear\]$r$p"
                        else
-                               PS1="$ps1pc_start ($c${b##refs/heads/}${f:+ $f}$r$p)$ps1pc_end"
+                               gitstring="$c${b##refs/heads/}${f:+ $f}$r$p"
                        fi
+                       gitstring=$(printf -- "$printf_format" "$gitstring")
+                       PS1="$ps1pc_start$gitstring$ps1pc_end"
                else
                        # NO color option unless in PROMPT_COMMAND mode
                        printf -- "$printf_format" "$c${b##refs/heads/}${f:+ $f}$r$p"
index 016cdadb4d8d5af3b0b68c21c1df3054dd1c5f17..c7006000a6f4a19fa4e5f4bf3fc543d4756a1f4d 100755 (executable)
@@ -31,7 +31,7 @@ import urllib
 # hg:
 # Emulate hg-git.
 # Only hg bookmarks are exported as git branches.
-# Commits are modified to preserve hg information and allow biridectionality.
+# Commits are modified to preserve hg information and allow bidirectionality.
 #
 
 NAME_RE = re.compile('^([^<>]+)')
index a94eb28092503c060cc725b720715d611d54527a..1d6198243667c655639781019d8d608e0791e00b 100755 (executable)
@@ -6,7 +6,7 @@
 # https://bitbucket.org/durin42/hg-git/src
 #
 
-test_description='Test biridectionality of remote-hg'
+test_description='Test bidirectionality of remote-hg'
 
 . ./test-lib.sh
 
index 4b852e2455bab324e3bd16e02ec712fbacbf34b0..9513f5e35b443c13cead1f73a27b5e76f94e8d66 100755 (executable)
@@ -1,38 +1,70 @@
-#!/usr/bin/perl -w
-my %mailmap = ();
-open I, "<", ".mailmap";
-while (<I>) {
-       chomp;
-       next if /^#/;
-       if (my ($author, $mail) = /^(.*?)\s+<(.+)>$/) {
-               $mailmap{$mail} = $author;
-       }
+#!/usr/bin/perl
+
+use warnings 'all';
+use strict;
+use Getopt::Long;
+
+my $match_emails;
+my $match_names;
+my $order_by = 'count';
+Getopt::Long::Configure(qw(bundling));
+GetOptions(
+       'emails|e!' => \$match_emails,
+       'names|n!'  => \$match_names,
+       'count|c'   => sub { $order_by = 'count' },
+       'time|t'    => sub { $order_by = 'stamp' },
+) or exit 1;
+$match_emails = 1 unless $match_names;
+
+my $email = {};
+my $name = {};
+
+open(my $fh, '-|', "git log --format='%at <%aE> %aN'");
+while(<$fh>) {
+       my ($t, $e, $n) = /(\S+) <(\S+)> (.*)/;
+       mark($email, $e, $n, $t);
+       mark($name, $n, $e, $t);
 }
-close I;
-
-my %mail2author = ();
-open I, "git log --pretty='format:%ae  %an' |";
-while (<I>) {
-       chomp;
-       my ($mail, $author) = split(/\t/, $_);
-       next if exists $mailmap{$mail};
-       $mail2author{$mail} ||= {};
-       $mail2author{$mail}{$author} ||= 0;
-       $mail2author{$mail}{$author}++;
+close($fh);
+
+if ($match_emails) {
+       foreach my $e (dups($email)) {
+               foreach my $n (vals($email->{$e})) {
+                       show($n, $e, $email->{$e}->{$n});
+               }
+               print "\n";
+       }
 }
-close I;
-
-while (my ($mail, $authorcount) = each %mail2author) {
-       # %$authorcount is ($author => $count);
-       # sort and show the names from the most frequent ones.
-       my @names = (map { $_->[0] }
-               sort { $b->[1] <=> $a->[1] }
-               map { [$_, $authorcount->{$_}] }
-               keys %$authorcount);
-       if (1 < @names) {
-               for (@names) {
-                       print "$_ <$mail>\n";
+if ($match_names) {
+       foreach my $n (dups($name)) {
+               foreach my $e (vals($name->{$n})) {
+                       show($n, $e, $name->{$n}->{$e});
                }
+               print "\n";
        }
 }
+exit 0;
 
+sub mark {
+       my ($h, $k, $v, $t) = @_;
+       my $e = $h->{$k}->{$v} ||= { count => 0, stamp => 0 };
+       $e->{count}++;
+       $e->{stamp} = $t unless $t < $e->{stamp};
+}
+
+sub dups {
+       my $h = shift;
+       return grep { keys($h->{$_}) > 1 } keys($h);
+}
+
+sub vals {
+       my $h = shift;
+       return sort {
+               $h->{$b}->{$order_by} <=> $h->{$a}->{$order_by}
+       } keys($h);
+}
+
+sub show {
+       my ($n, $e, $h) = @_;
+       print "$n <$e> ($h->{$order_by})\n";
+}
index 7e77c9d0229e949c034c8c46811e19d2325e9cca..91360a3d7f0ad2d589dfe0365d4456d56853e7c0 100644 (file)
@@ -1,4 +1,5 @@
 *~
+git-subtree
 git-subtree.xml
 git-subtree.1
 mainline
index 0c44fda011bcfd39fd8c464c35017df620a91ff9..c5bce41ac7ccd88013f3de3c663f980d2277938c 100644 (file)
@@ -93,7 +93,7 @@ pull::
        repository.
        
 push::
-       Does a 'split' (see above) using the <prefix> supplied
+       Does a 'split' (see below) using the <prefix> supplied
        and then does a 'git push' to push the result to the 
        repository and refspec. This can be used to push your
        subtree to different branches of the remote repository.
index fca1e17251f1f414a1d97bf6e6240bdf20daa648..8f16d069721c5b9885b2e700981618878b54191e 100644 (file)
@@ -17,16 +17,6 @@ To install:
 
   1. Copy these files to vim's syntax directory $HOME/.vim/syntax
   2. To auto-detect the editing of various git-related filetypes:
-       $ cat >>$HOME/.vim/filetype.vim <<'EOF'
-       autocmd BufNewFile,BufRead *.git/COMMIT_EDITMSG    setf gitcommit
-       autocmd BufNewFile,BufRead *.git/config,.gitconfig setf gitconfig
-       autocmd BufNewFile,BufRead git-rebase-todo         setf gitrebase
-       autocmd BufNewFile,BufRead .msg.[0-9]*
-               \ if getline(1) =~ '^From.*# This line is ignored.$' |
-               \   setf gitsendemail |
-               \ endif
-       autocmd BufNewFile,BufRead *.git/**
-               \ if getline(1) =~ '^\x\{40\}\>\|^ref: ' |
-               \   setf git |
-               \ endif
-       EOF
+
+       $ curl http://ftp.vim.org/pub/vim/runtime/filetype.vim |
+               sed -ne '/^" Git$/, /^$/ p' >>$HOME/.vim/filetype.vim
diff --git a/dir.c b/dir.c
index 5a83aa7897f270279c403778f43aea6db1efc5af..a473ca23fba1272483bd8041e1bf901b8e12c32e 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -732,7 +732,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)
 
 static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 {
-       if (cache_name_exists(pathname, len, ignore_case))
+       if (!(dir->flags & DIR_SHOW_IGNORED) &&
+           cache_name_exists(pathname, len, ignore_case))
                return NULL;
 
        ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
@@ -834,8 +835,9 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
  * traversal routine.
  *
  * Case 1: If we *already* have entries in the index under that
- * directory name, we always recurse into the directory to see
- * all the files.
+ * directory name, we recurse into the directory to see all the files,
+ * unless the directory is excluded and we want to show ignored
+ * directories
  *
  * Case 2: If we *already* have that directory name as a gitlink,
  * we always continue to see it as a gitlink, regardless of whether
@@ -849,6 +851,9 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
  *      just a directory, unless "hide_empty_directories" is
  *      also true and the directory is empty, in which case
  *      we just ignore it entirely.
+ *      if we are looking for ignored directories, look if it
+ *      contains only ignored files to decide if it must be shown as
+ *      ignored or not.
  *  (b) if it looks like a git directory, and we don't have
  *      'no_gitlinks' set we treat it as a gitlink, and show it
  *      as a directory.
@@ -861,12 +866,15 @@ enum directory_treatment {
 };
 
 static enum directory_treatment treat_directory(struct dir_struct *dir,
-       const char *dirname, int len,
+       const char *dirname, int len, int exclude,
        const struct path_simplify *simplify)
 {
        /* The "len-1" is to strip the final '/' */
        switch (directory_exists_in_index(dirname, len-1)) {
        case index_directory:
+               if ((dir->flags & DIR_SHOW_OTHER_DIRECTORIES) && exclude)
+                       break;
+
                return recurse_into_directory;
 
        case index_gitdir:
@@ -886,13 +894,68 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
        }
 
        /* This is the "show_other_directories" case */
-       if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
+
+       /*
+        * We are looking for ignored files and our directory is not ignored,
+        * check if it contains only ignored files
+        */
+       if ((dir->flags & DIR_SHOW_IGNORED) && !exclude) {
+               int ignored;
+               dir->flags &= ~DIR_SHOW_IGNORED;
+               dir->flags |= DIR_HIDE_EMPTY_DIRECTORIES;
+               ignored = read_directory_recursive(dir, dirname, len, 1, simplify);
+               dir->flags &= ~DIR_HIDE_EMPTY_DIRECTORIES;
+               dir->flags |= DIR_SHOW_IGNORED;
+
+               return ignored ? ignore_directory : show_directory;
+       }
+       if (!(dir->flags & DIR_SHOW_IGNORED) &&
+           !(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
                return show_directory;
        if (!read_directory_recursive(dir, dirname, len, 1, simplify))
                return ignore_directory;
        return show_directory;
 }
 
+/*
+ * Decide what to do when we find a file while traversing the
+ * filesystem. Mostly two cases:
+ *
+ *  1. We are looking for ignored files
+ *   (a) File is ignored, include it
+ *   (b) File is in ignored path, include it
+ *   (c) File is not ignored, exclude it
+ *
+ *  2. Other scenarios, include the file if not excluded
+ *
+ * Return 1 for exclude, 0 for include.
+ */
+static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude, int *dtype)
+{
+       struct path_exclude_check check;
+       int exclude_file = 0;
+
+       if (exclude)
+               exclude_file = !(dir->flags & DIR_SHOW_IGNORED);
+       else if (dir->flags & DIR_SHOW_IGNORED) {
+               /* Always exclude indexed files */
+               struct cache_entry *ce = index_name_exists(&the_index,
+                   path->buf, path->len, ignore_case);
+
+               if (ce)
+                       return 1;
+
+               path_exclude_check_init(&check, dir);
+
+               if (!path_excluded(&check, path->buf, path->len, dtype))
+                       exclude_file = 1;
+
+               path_exclude_check_clear(&check);
+       }
+
+       return exclude_file;
+}
+
 /*
  * This is an inexact early pruning of any recursive directory
  * reading - if the path cannot possibly be in the pathspec,
@@ -1031,27 +1094,14 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
        if (dtype == DT_UNKNOWN)
                dtype = get_dtype(de, path->buf, path->len);
 
-       /*
-        * Do we want to see just the ignored files?
-        * We still need to recurse into directories,
-        * even if we don't ignore them, since the
-        * directory may contain files that we do..
-        */
-       if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
-               if (dtype != DT_DIR)
-                       return path_ignored;
-       }
-
        switch (dtype) {
        default:
                return path_ignored;
        case DT_DIR:
                strbuf_addch(path, '/');
-               switch (treat_directory(dir, path->buf, path->len, simplify)) {
+
+               switch (treat_directory(dir, path->buf, path->len, exclude, simplify)) {
                case show_directory:
-                       if (exclude != !!(dir->flags
-                                         & DIR_SHOW_IGNORED))
-                               return path_ignored;
                        break;
                case recurse_into_directory:
                        return path_recurse;
@@ -1061,7 +1111,12 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
                break;
        case DT_REG:
        case DT_LNK:
-               break;
+               switch (treat_file(dir, path, exclude, &dtype)) {
+               case 1:
+                       return path_ignored;
+               default:
+                       break;
+               }
        }
        return path_handled;
 }
index d8340031d24828483697c10257806efedfe041f5..27bdecdaf3d99d3179737e07be971d2458408660 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "strbuf.h"
 #include "run-command.h"
+#include "sigchain.h"
 
 #ifndef DEFAULT_EDITOR
 #define DEFAULT_EDITOR "vi"
@@ -37,8 +38,25 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en
 
        if (strcmp(editor, ":")) {
                const char *args[] = { editor, path, NULL };
+               struct child_process p;
+               int ret, sig;
 
-               if (run_command_v_opt_cd_env(args, RUN_USING_SHELL, NULL, env))
+               memset(&p, 0, sizeof(p));
+               p.argv = args;
+               p.env = env;
+               p.use_shell = 1;
+               if (start_command(&p) < 0)
+                       return error("unable to start editor '%s'", editor);
+
+               sigchain_push(SIGINT, SIG_IGN);
+               sigchain_push(SIGQUIT, SIG_IGN);
+               ret = finish_command(&p);
+               sig = ret - 128;
+               sigchain_pop(SIGINT);
+               sigchain_pop(SIGQUIT);
+               if (sig == SIGINT || sig == SIGQUIT)
+                       raise(sig);
+               if (ret)
                        return error("There was a problem with the editor '%s'.",
                                        editor);
        }
index c682d34094d618734ac52d6d7e15a6c10ccfdeb6..202130f888bee14e73b8cc108f39f2da8a14d23b 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -334,7 +334,7 @@ split_patches () {
                        # Since we cannot guarantee that the commit message is in
                        # git-friendly format, we put no Subject: line and just consume
                        # all of the message as the body
-                       perl -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 }
+                       LANG=C LC_ALL=C perl -M'POSIX qw(strftime)' -ne 'BEGIN { $subject = 0 }
                                if ($subject) { print ; }
                                elsif (/^\# User /) { s/\# User/From:/ ; print ; }
                                elsif (/^\# Date /) {
@@ -664,7 +664,7 @@ do
                        sed -e '1,/^$/d' >"$dotest/msg-clean"
                        echo "$commit" >"$dotest/original-commit"
                        get_author_ident_from_commit "$commit" >"$dotest/author-script"
-                       git diff-tree --root --binary "$commit" >"$dotest/patch"
+                       git diff-tree --root --binary --full-index "$commit" >"$dotest/patch"
                else
                        git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
                                <"$dotest/$msgnum" >"$dotest/info" ||
index 2e79b8a2f379d7c72a0934b36c7538db2143c722..590d5d3188aed8f3a2b0b7050f2502b28cb4f5fa 100644 (file)
@@ -637,8 +637,12 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
-/* Call access(2), but warn for any error besides ENOENT. */
+/*
+ * Call access(2), but warn for any error except "missing file"
+ * (ENOENT or ENOTDIR).
+ */
 int access_or_warn(const char *path, int mode);
+int access_or_die(const char *path, int mode);
 
 /* Warn on an inaccessible file that ought to be accessible */
 void warn_on_inaccessible(const char *path);
index 0a31ebd82020f3aca0020d357c2028d5e7b5e37b..344f1206d111a57ec529c34785ff8b1a6537e4d1 100755 (executable)
@@ -26,6 +26,7 @@
 use IO::Pipe;
 use POSIX qw(strftime tzset dup2 ENOENT);
 use IPC::Open2;
+use Git qw(get_tz_offset);
 
 $SIG{'PIPE'}="IGNORE";
 set_timezone('UTC');
@@ -864,7 +865,9 @@ sub commit {
        }
 
        set_timezone($author_tz);
-       my $commit_date = strftime("%s %z", localtime($date));
+       # $date is in the seconds since epoch format
+       my $tz_offset = get_tz_offset($date);
+       my $commit_date = "$date $tz_offset";
        set_timezone('UTC');
        $ENV{GIT_AUTHOR_NAME} = $author_name;
        $ENV{GIT_AUTHOR_EMAIL} = $author_email;
index 3d0fe0cd93b393a5f376aa10505e927fbed37f8f..b00ed95dba9c035ee812d3a2d6db2d13a1944a33 100755 (executable)
@@ -40,7 +40,7 @@ launch_merge_tool () {
        # the user with the real $MERGED name before launching $merge_tool.
        if should_prompt
        then
-               printf "\nViewing: '$MERGED'\n"
+               printf "\nViewing: '%s'\n" "$MERGED"
                if use_ext_cmd
                then
                        printf "Launch '%s' [Y/n]: " \
index c50e18a8998c1f4ca1449e1733f76cb769f501b9..012afa55494cc968831b8115f9e2956f107bbb45 100755 (executable)
@@ -440,7 +440,7 @@ then
 fi
 
 printf "Merging:\n"
-printf "$files\n"
+printf "%s\n" "$files"
 
 IFS='
 '
index 551aec9417401dcd7ef526dd6c9b554e5194f861..0682e61e90dca3f88f399c20aa19c5336274bc95 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
 import tempfile, getopt, os.path, time, platform
 import re, shutil
 
+try:
+    from subprocess import CalledProcessError
+except ImportError:
+    # from python2.7:subprocess.py
+    # Exception classes used by this module.
+    class CalledProcessError(Exception):
+        """This exception is raised when a process run by check_call() returns
+        a non-zero exit status.  The exit status will be stored in the
+        returncode attribute."""
+        def __init__(self, returncode, cmd):
+            self.returncode = returncode
+            self.cmd = cmd
+        def __str__(self):
+            return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
+
 verbose = False
 
 # Only labels/tags matching this will be imported/exported
@@ -152,13 +167,17 @@ def system(cmd):
     expand = isinstance(cmd,basestring)
     if verbose:
         sys.stderr.write("executing %s\n" % str(cmd))
-    subprocess.check_call(cmd, shell=expand)
+    retcode = subprocess.call(cmd, shell=expand)
+    if retcode:
+        raise CalledProcessError(retcode, cmd)
 
 def p4_system(cmd):
     """Specifically invoke p4 as the system command. """
     real_cmd = p4_build_cmd(cmd)
     expand = isinstance(real_cmd, basestring)
-    subprocess.check_call(real_cmd, shell=expand)
+    retcode = subprocess.call(real_cmd, shell=expand)
+    if retcode:
+        raise CalledProcessError(retcode, real_cmd)
 
 def p4_integrate(src, dest):
     p4_system(["integrate", "-Dt", wildcard_encode(src), wildcard_encode(dest)])
@@ -742,7 +761,8 @@ def wildcard_encode(path):
     return path
 
 def wildcard_present(path):
-    return path.translate(None, "*#@%") != path
+    m = re.search("[*#@%]", path)
+    return m is not None
 
 class Command:
     def __init__(self):
@@ -3103,7 +3123,9 @@ def run(self, args):
         init_cmd = [ "git", "init" ]
         if self.cloneBare:
             init_cmd.append("--bare")
-        subprocess.check_call(init_cmd)
+        retcode = subprocess.call(init_cmd)
+        if retcode:
+            raise CalledProcessError(retcode, init_cmd)
 
         if not P4Sync.run(self, depotPaths):
             return False
index 44901d53c43d972e03a71bfbe0b769f2e8f22d7b..8ed7fccc18507b6f3e2508bb117ce056a764de77 100644 (file)
@@ -190,6 +190,11 @@ is_empty_commit() {
        test "$tree" = "$ptree"
 }
 
+is_merge_commit()
+{
+       git rev-parse --verify --quiet "$1"^2 >/dev/null 2>&1
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -874,7 +879,7 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 while read -r shortsha1 rest
 do
 
-       if test -z "$keep_empty" && is_empty_commit $shortsha1
+       if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
        then
                comment_out="# "
        else
index 94c7f76a156f1eaa4c622db267710f2982cf7826..be809e5b59394a4fd2f4f2b73cad6bac47a39600 100755 (executable)
@@ -1285,10 +1285,10 @@ sub send_message {
                }
 
                if (defined $input_format && $input_format eq 'mbox') {
-                       if (/^Subject:\s+(.*)$/) {
+                       if (/^Subject:\s+(.*)$/i) {
                                $subject = $1;
                        }
-                       elsif (/^From:\s+(.*)$/) {
+                       elsif (/^From:\s+(.*)$/i) {
                                ($author, $author_encoding) = unquote_rfc2047($1);
                                next if $suppress_cc{'author'};
                                next if $suppress_cc{'self'} and $author eq $sender;
@@ -1296,14 +1296,14 @@ sub send_message {
                                        $1, $_) unless $quiet;
                                push @cc, $1;
                        }
-                       elsif (/^To:\s+(.*)$/) {
+                       elsif (/^To:\s+(.*)$/i) {
                                foreach my $addr (parse_address_line($1)) {
                                        printf("(mbox) Adding to: %s from line '%s'\n",
                                                $addr, $_) unless $quiet;
                                        push @to, $addr;
                                }
                        }
-                       elsif (/^Cc:\s+(.*)$/) {
+                       elsif (/^Cc:\s+(.*)$/i) {
                                foreach my $addr (parse_address_line($1)) {
                                        if (unquote_rfc2047($addr) eq $sender) {
                                                next if ($suppress_cc{'self'});
@@ -1325,7 +1325,7 @@ sub send_message {
                        elsif (/^Message-Id: (.*)/i) {
                                $message_id = $1;
                        }
-                       elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
+                       elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
                                push @xh, $_;
                        }
 
index 22f0aed6db366c3d4a291b3ae646c45002ff86c1..795edd2852aa1c680c3db1776bb84aca7662899d 100644 (file)
 # But we protect ourselves from such a user mistake nevertheless.
 unset CDPATH
 
-# Similarly for IFS
-unset IFS
+# Similarly for IFS, but some shells (e.g. FreeBSD 7.2) are buggy and
+# do not equate an unset IFS with IFS with the default, so here is
+# an explicit SP HT LF.
+IFS='  
+'
 
 git_broken_path_fix () {
        case ":$PATH:" in
index 0f207f2e20b0c3c30e62c1fd6f0526d38868776f..1309196d27e675013825cdac8afd6d7328e44b1f 100755 (executable)
@@ -1556,7 +1556,7 @@ sub sanitize {
        return undef unless defined $str;
 
        $str = to_utf8($str);
-       $str =~ s|([[:cntrl:]])|($1 =~ /[\t\n\r]/ ? $1 : quot_cec($1))|eg;
+       $str =~ s|([[:cntrl:]])|(index("\t\n\r", $1) != -1 ? $1 : quot_cec($1))|eg;
        return $str;
 }
 
@@ -2068,7 +2068,7 @@ sub picon_url {
        if (!$avatar_cache{$email}) {
                my ($user, $domain) = split('@', $email);
                $avatar_cache{$email} =
-                       "http://www.cs.indiana.edu/cgi-pub/kinzler/piconsearch.cgi/" .
+                       "//www.cs.indiana.edu/cgi-pub/kinzler/piconsearch.cgi/" .
                        "$domain/$user/" .
                        "users+domains+unknown/up/single";
        }
@@ -2083,7 +2083,7 @@ sub gravatar_url {
        my $email = lc shift;
        my $size = shift;
        $avatar_cache{$email} ||=
-               "http://www.gravatar.com/avatar/" .
+               "//www.gravatar.com/avatar/" .
                        Digest::MD5::md5_hex($email) . "?s=";
        return $avatar_cache{$email} . $size;
 }
@@ -5528,23 +5528,30 @@ sub fill_project_list_info {
 
 sub sort_projects_list {
        my ($projlist, $order) = @_;
-       my @projects;
 
-       my %order_info = (
-               project => { key => 'path', type => 'str' },
-               descr => { key => 'descr_long', type => 'str' },
-               owner => { key => 'owner', type => 'str' },
-               age => { key => 'age', type => 'num' }
-       );
-       my $oi = $order_info{$order};
-       return @$projlist unless defined $oi;
-       if ($oi->{'type'} eq 'str') {
-               @projects = sort {$a->{$oi->{'key'}} cmp $b->{$oi->{'key'}}} @$projlist;
-       } else {
-               @projects = sort {$a->{$oi->{'key'}} <=> $b->{$oi->{'key'}}} @$projlist;
+       sub order_str {
+               my $key = shift;
+               return sub { $a->{$key} cmp $b->{$key} };
        }
 
-       return @projects;
+       sub order_num_then_undef {
+               my $key = shift;
+               return sub {
+                       defined $a->{$key} ?
+                               (defined $b->{$key} ? $a->{$key} <=> $b->{$key} : -1) :
+                               (defined $b->{$key} ? 1 : 0)
+               };
+       }
+
+       my %orderings = (
+               project => order_str('path'),
+               descr => order_str('descr_long'),
+               owner => order_str('owner'),
+               age => order_num_then_undef('age'),
+       );
+
+       my $ordering = $orderings{$order};
+       return defined $ordering ? sort $ordering @$projlist : @$projlist;
 }
 
 # returns a hash of categories, containing the list of project
index 0863c618007a02fa20c27b62614de8a554128d0c..5f142f619855ccd664a84be366bf6877a48e6da4 100644 (file)
@@ -130,8 +130,10 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
        write_in_full(gpg.in, payload, payload_size);
        close(gpg.in);
 
-       if (gpg_output)
+       if (gpg_output) {
                strbuf_read(gpg_output, gpg.err, 0);
+               close(gpg.err);
+       }
        ret = finish_command(&gpg);
 
        unlink_or_warn(path);
diff --git a/graph.c b/graph.c
index e864fe2c6a21379398e454e60627e78a63a09462..391a712e5eafbc05b8d4b739d96aaca0dd481460 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -1227,7 +1227,7 @@ void graph_show_commit(struct git_graph *graph)
        if (!graph)
                return;
 
-       while (!shown_commit_line) {
+       while (!shown_commit_line && !graph_is_commit_finished(graph)) {
                shown_commit_line = graph_next_line(graph, &msgbuf);
                fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
                if (!shown_commit_line)
diff --git a/help.c b/help.c
index 2a42ec6d1f312b573d7b1da1a15471d21efc5b4d..1dfa0b05827e6e75dc463092b2838cd1c991623c 100644 (file)
--- a/help.c
+++ b/help.c
@@ -223,6 +223,23 @@ void list_commands(unsigned int colopts,
        }
 }
 
+void list_common_cmds_help(void)
+{
+       int i, longest = 0;
+
+       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+               if (longest < strlen(common_cmds[i].name))
+                       longest = strlen(common_cmds[i].name);
+       }
+
+       puts(_("The most commonly used git commands are:"));
+       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+               printf("   %s   ", common_cmds[i].name);
+               mput_char(' ', longest - strlen(common_cmds[i].name));
+               puts(_(common_cmds[i].help));
+       }
+}
+
 int is_in_cmdlist(struct cmdnames *c, const char *s)
 {
        int i;
index 8701c1215d21cd0413c1d69be91b309984cf6b1f..ba45b7b501b901e39b34cb44b41cb758dc4ad293 100644 (file)
@@ -1560,7 +1560,7 @@ static int remote_exists(const char *path)
 
        sprintf(url, "%s%s", repo->url, path);
 
-       switch (http_get_strbuf(url, NULL, 0)) {
+       switch (http_get_strbuf(url, NULL, NULL, 0)) {
        case HTTP_OK:
                ret = 1;
                break;
@@ -1584,7 +1584,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        url = xmalloc(strlen(repo->url) + strlen(path) + 1);
        sprintf(url, "%s%s", repo->url, path);
 
-       if (http_get_strbuf(url, &buffer, 0) != HTTP_OK)
+       if (http_get_strbuf(url, NULL, &buffer, 0) != HTTP_OK)
                die("Couldn't get %s for remote symref\n%s", url,
                    curl_errorstr);
        free(url);
diff --git a/http.c b/http.c
index 0a8abf3be369a18fae8e743d4cc9b5f2c2f63f03..d9d1aad3be468394e39966c0b45e7e101b387b0c 100644 (file)
--- a/http.c
+++ b/http.c
@@ -236,6 +236,7 @@ static int has_cert_password(void)
                return 0;
        if (!cert_auth.password) {
                cert_auth.protocol = xstrdup("cert");
+               cert_auth.username = xstrdup("");
                cert_auth.path = xstrdup(ssl_cert);
                credential_fill(&cert_auth);
        }
@@ -787,7 +788,8 @@ int handle_curl_result(struct slot_results *results)
 #define HTTP_REQUEST_STRBUF    0
 #define HTTP_REQUEST_FILE      1
 
-static int http_request(const char *url, void *result, int target, int options)
+static int http_request(const char *url, struct strbuf *type,
+                       void *result, int target, int options)
 {
        struct active_request_slot *slot;
        struct slot_results results;
@@ -837,24 +839,37 @@ static int http_request(const char *url, void *result, int target, int options)
                ret = HTTP_START_FAILED;
        }
 
+       if (type) {
+               char *t;
+               strbuf_reset(type);
+               curl_easy_getinfo(slot->curl, CURLINFO_CONTENT_TYPE, &t);
+               if (t)
+                       strbuf_addstr(type, t);
+       }
+
        curl_slist_free_all(headers);
        strbuf_release(&buf);
 
        return ret;
 }
 
-static int http_request_reauth(const char *url, void *result, int target,
+static int http_request_reauth(const char *url,
+                              struct strbuf *type,
+                              void *result, int target,
                               int options)
 {
-       int ret = http_request(url, result, target, options);
+       int ret = http_request(url, type, result, target, options);
        if (ret != HTTP_REAUTH)
                return ret;
-       return http_request(url, result, target, options);
+       return http_request(url, type, result, target, options);
 }
 
-int http_get_strbuf(const char *url, struct strbuf *result, int options)
+int http_get_strbuf(const char *url,
+                   struct strbuf *type,
+                   struct strbuf *result, int options)
 {
-       return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options);
+       return http_request_reauth(url, type, result,
+                                  HTTP_REQUEST_STRBUF, options);
 }
 
 /*
@@ -877,7 +892,7 @@ static int http_get_file(const char *url, const char *filename, int options)
                goto cleanup;
        }
 
-       ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
+       ret = http_request_reauth(url, NULL, result, HTTP_REQUEST_FILE, options);
        fclose(result);
 
        if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename))
@@ -903,7 +918,7 @@ int http_fetch_ref(const char *base, struct ref *ref)
        int ret = -1;
 
        url = quote_ref_url(base, ref->name);
-       if (http_get_strbuf(url, &buffer, HTTP_NO_CACHE) == HTTP_OK) {
+       if (http_get_strbuf(url, NULL, &buffer, HTTP_NO_CACHE) == HTTP_OK) {
                strbuf_rtrim(&buffer);
                if (buffer.len == 40)
                        ret = get_sha1_hex(buffer.buf, ref->old_sha1);
@@ -996,7 +1011,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
        strbuf_addstr(&buf, "objects/info/packs");
        url = strbuf_detach(&buf, NULL);
 
-       ret = http_get_strbuf(url, &buf, HTTP_NO_CACHE);
+       ret = http_get_strbuf(url, NULL, &buf, HTTP_NO_CACHE);
        if (ret != HTTP_OK)
                goto cleanup;
 
diff --git a/http.h b/http.h
index 0a80d303e369b4adf77ca131c732ba39a990610d..25d19313983f0d0a11ab50dffbb623b105c8960a 100644 (file)
--- a/http.h
+++ b/http.h
@@ -132,7 +132,7 @@ extern char *get_remote_object_url(const char *url, const char *hex,
  *
  * If the result pointer is NULL, a HTTP HEAD request is made instead of GET.
  */
-int http_get_strbuf(const char *url, struct strbuf *result, int options);
+int http_get_strbuf(const char *url, struct strbuf *content_type, struct strbuf *result, int options);
 
 /*
  * Prints an error message using error() containing url and curl_errorstr,
diff --git a/ident.c b/ident.c
index ac9672f607909111167559e3aa58e1585f05d0d8..1c123e685fbfbfcd5289958adc54a6cd48351628 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -46,6 +46,7 @@ static void copy_gecos(const struct passwd *w, struct strbuf *name)
 static int add_mailname_host(struct strbuf *buf)
 {
        FILE *mailname;
+       struct strbuf mailnamebuf = STRBUF_INIT;
 
        mailname = fopen("/etc/mailname", "r");
        if (!mailname) {
@@ -54,14 +55,17 @@ static int add_mailname_host(struct strbuf *buf)
                                strerror(errno));
                return -1;
        }
-       if (strbuf_getline(buf, mailname, '\n') == EOF) {
+       if (strbuf_getline(&mailnamebuf, mailname, '\n') == EOF) {
                if (ferror(mailname))
                        warning("cannot read /etc/mailname: %s",
                                strerror(errno));
+               strbuf_release(&mailnamebuf);
                fclose(mailname);
                return -1;
        }
        /* success! */
+       strbuf_addbuf(buf, &mailnamebuf);
+       strbuf_release(&mailnamebuf);
        fclose(mailname);
        return 0;
 }
index d42e4712972794f055aec6630ba86797d7e5343c..ef500111ec0bca6514e519d39e7a269a7342cddf 100644 (file)
@@ -31,6 +31,7 @@ typedef void *SSL;
 #else
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
+#include <openssl/x509v3.h>
 #endif
 
 struct store_conf {
@@ -266,12 +267,64 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
        }
 }
 
+#ifdef NO_OPENSSL
 static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
 {
-#ifdef NO_OPENSSL
        fprintf(stderr, "SSL requested but SSL support not compiled in\n");
        return -1;
+}
+
 #else
+
+static int host_matches(const char *host, const char *pattern)
+{
+       if (pattern[0] == '*' && pattern[1] == '.') {
+               pattern += 2;
+               if (!(host = strchr(host, '.')))
+                       return 0;
+               host++;
+       }
+
+       return *host && *pattern && !strcasecmp(host, pattern);
+}
+
+static int verify_hostname(X509 *cert, const char *hostname)
+{
+       int len;
+       X509_NAME *subj;
+       char cname[1000];
+       int i, found;
+       STACK_OF(GENERAL_NAME) *subj_alt_names;
+
+       /* try the DNS subjectAltNames */
+       found = 0;
+       if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) {
+               int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
+               for (i = 0; !found && i < num_subj_alt_names; i++) {
+                       GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
+                       if (subj_alt_name->type == GEN_DNS &&
+                           strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
+                           host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data)))
+                               found = 1;
+               }
+               sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
+       }
+       if (found)
+               return 0;
+
+       /* try the common name */
+       if (!(subj = X509_get_subject_name(cert)))
+               return error("cannot get certificate subject");
+       if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
+               return error("cannot get certificate common name");
+       if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
+               return 0;
+       return error("certificate owner '%s' does not match hostname '%s'",
+                    cname, hostname);
+}
+
+static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+{
 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
        const SSL_METHOD *meth;
 #else
@@ -279,6 +332,7 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
 #endif
        SSL_CTX *ctx;
        int ret;
+       X509 *cert;
 
        SSL_library_init();
        SSL_load_error_strings();
@@ -322,9 +376,18 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
                return -1;
        }
 
+       if (verify) {
+               /* make sure the hostname matches that of the certificate */
+               cert = SSL_get_peer_certificate(sock->ssl);
+               if (!cert)
+                       return error("unable to get peer certificate.");
+               if (verify_hostname(cert, server.host) < 0)
+                       return -1;
+       }
+
        return 0;
-#endif
 }
+#endif
 
 static int socket_read(struct imap_socket *sock, char *buf, int len)
 {
diff --git a/merge-blobs.c b/merge-blobs.c
new file mode 100644 (file)
index 0000000..57211bc
--- /dev/null
@@ -0,0 +1,124 @@
+#include "cache.h"
+#include "run-command.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
+#include "blob.h"
+#include "merge-blobs.h"
+
+static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
+{
+       void *buf;
+       unsigned long size;
+       enum object_type type;
+
+       buf = read_sha1_file(obj->object.sha1, &type, &size);
+       if (!buf)
+               return -1;
+       if (type != OBJ_BLOB)
+               return -1;
+       f->ptr = buf;
+       f->size = size;
+       return 0;
+}
+
+static void free_mmfile(mmfile_t *f)
+{
+       free(f->ptr);
+}
+
+static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)
+{
+       int merge_status;
+       mmbuffer_t res;
+
+       /*
+        * 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", NULL);
+       if (merge_status < 0)
+               return NULL;
+
+       *size = res.size;
+       return res.ptr;
+}
+
+static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
+{
+       int i;
+       mmfile_t *dst = priv_;
+
+       for (i = 0; i < nbuf; i++) {
+               memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
+               dst->size += mb[i].size;
+       }
+       return 0;
+}
+
+static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
+{
+       unsigned long size = f1->size < f2->size ? f1->size : f2->size;
+       void *ptr = xmalloc(size);
+       xpparam_t xpp;
+       xdemitconf_t xecfg;
+       xdemitcb_t ecb;
+
+       memset(&xpp, 0, sizeof(xpp));
+       xpp.flags = 0;
+       memset(&xecfg, 0, sizeof(xecfg));
+       xecfg.ctxlen = 3;
+       xecfg.flags = XDL_EMIT_COMMON;
+       ecb.outf = common_outf;
+
+       res->ptr = ptr;
+       res->size = 0;
+
+       ecb.priv = res;
+       return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
+}
+
+void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
+{
+       void *res = NULL;
+       mmfile_t f1, f2, common;
+
+       /*
+        * Removed in either branch?
+        *
+        * NOTE! This depends on the caller having done the
+        * proper warning about removing a file that got
+        * modified in the other branch!
+        */
+       if (!our || !their) {
+               enum object_type type;
+               if (base)
+                       return NULL;
+               if (!our)
+                       our = their;
+               return read_sha1_file(our->object.sha1, &type, size);
+       }
+
+       if (fill_mmfile_blob(&f1, our) < 0)
+               goto out_no_mmfile;
+       if (fill_mmfile_blob(&f2, their) < 0)
+               goto out_free_f1;
+
+       if (base) {
+               if (fill_mmfile_blob(&common, base) < 0)
+                       goto out_free_f2_f1;
+       } else {
+               if (generate_common_file(&common, &f1, &f2) < 0)
+                       goto out_free_f2_f1;
+       }
+       res = three_way_filemerge(path, &common, &f1, &f2, size);
+       free_mmfile(&common);
+out_free_f2_f1:
+       free_mmfile(&f2);
+out_free_f1:
+       free_mmfile(&f1);
+out_no_mmfile:
+       return res;
+}
diff --git a/merge-blobs.h b/merge-blobs.h
new file mode 100644 (file)
index 0000000..62b569e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef MERGE_BLOBS_H
+#define MERGE_BLOBS_H
+
+#include "blob.h"
+
+extern void *merge_blobs(const char *, struct blob *, struct blob *, struct blob *, unsigned long *);
+
+#endif /* MERGE_BLOBS_H */
diff --git a/merge-file.c b/merge-file.c
deleted file mode 100644 (file)
index 7845528..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#include "cache.h"
-#include "run-command.h"
-#include "xdiff-interface.h"
-#include "ll-merge.h"
-#include "blob.h"
-#include "merge-file.h"
-
-static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
-{
-       void *buf;
-       unsigned long size;
-       enum object_type type;
-
-       buf = read_sha1_file(obj->object.sha1, &type, &size);
-       if (!buf)
-               return -1;
-       if (type != OBJ_BLOB)
-               return -1;
-       f->ptr = buf;
-       f->size = size;
-       return 0;
-}
-
-static void free_mmfile(mmfile_t *f)
-{
-       free(f->ptr);
-}
-
-static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)
-{
-       int merge_status;
-       mmbuffer_t res;
-
-       /*
-        * 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", NULL);
-       if (merge_status < 0)
-               return NULL;
-
-       *size = res.size;
-       return res.ptr;
-}
-
-static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
-{
-       int i;
-       mmfile_t *dst = priv_;
-
-       for (i = 0; i < nbuf; i++) {
-               memcpy(dst->ptr + dst->size, mb[i].ptr, mb[i].size);
-               dst->size += mb[i].size;
-       }
-       return 0;
-}
-
-static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
-{
-       unsigned long size = f1->size < f2->size ? f1->size : f2->size;
-       void *ptr = xmalloc(size);
-       xpparam_t xpp;
-       xdemitconf_t xecfg;
-       xdemitcb_t ecb;
-
-       memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = 0;
-       memset(&xecfg, 0, sizeof(xecfg));
-       xecfg.ctxlen = 3;
-       xecfg.flags = XDL_EMIT_COMMON;
-       ecb.outf = common_outf;
-
-       res->ptr = ptr;
-       res->size = 0;
-
-       ecb.priv = res;
-       return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
-}
-
-void *merge_file(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
-{
-       void *res = NULL;
-       mmfile_t f1, f2, common;
-
-       /*
-        * Removed in either branch?
-        *
-        * NOTE! This depends on the caller having done the
-        * proper warning about removing a file that got
-        * modified in the other branch!
-        */
-       if (!our || !their) {
-               enum object_type type;
-               if (base)
-                       return NULL;
-               if (!our)
-                       our = their;
-               return read_sha1_file(our->object.sha1, &type, size);
-       }
-
-       if (fill_mmfile_blob(&f1, our) < 0)
-               goto out_no_mmfile;
-       if (fill_mmfile_blob(&f2, their) < 0)
-               goto out_free_f1;
-
-       if (base) {
-               if (fill_mmfile_blob(&common, base) < 0)
-                       goto out_free_f2_f1;
-       } else {
-               if (generate_common_file(&common, &f1, &f2) < 0)
-                       goto out_free_f2_f1;
-       }
-       res = three_way_filemerge(path, &common, &f1, &f2, size);
-       free_mmfile(&common);
-out_free_f2_f1:
-       free_mmfile(&f2);
-out_free_f1:
-       free_mmfile(&f1);
-out_no_mmfile:
-       return res;
-}
diff --git a/merge-file.h b/merge-file.h
deleted file mode 100644 (file)
index 9b3b83a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef MERGE_FILE_H
-#define MERGE_FILE_H
-
-extern void *merge_file(const char *path, struct blob *base, struct blob *our,
-                       struct blob *their, unsigned long *size);
-
-#endif
index d8820604ca3535ce25796012412fe69f1cbdd37b..33ba5dc07c86a81f0989927b9a6167833815533f 100644 (file)
@@ -976,7 +976,7 @@ merge_file_special_markers(struct merge_options *o,
        return mfi;
 }
 
-static struct merge_file_info merge_file(struct merge_options *o,
+static struct merge_file_info merge_file_one(struct merge_options *o,
                                         const char *path,
                                         const unsigned char *o_sha, int o_mode,
                                         const unsigned char *a_sha, int a_mode,
@@ -1166,7 +1166,7 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
                struct merge_file_info mfi;
                struct diff_filespec other;
                struct diff_filespec *add;
-               mfi = merge_file(o, one->path,
+               mfi = merge_file_one(o, one->path,
                                 one->sha1, one->mode,
                                 a->sha1, a->mode,
                                 b->sha1, b->mode,
@@ -1450,7 +1450,7 @@ static int process_renames(struct merge_options *o,
                                       ren1_dst, branch2);
                                if (o->call_depth) {
                                        struct merge_file_info mfi;
-                                       mfi = merge_file(o, ren1_dst, null_sha1, 0,
+                                       mfi = merge_file_one(o, ren1_dst, null_sha1, 0,
                                                         ren1->pair->two->sha1, ren1->pair->two->mode,
                                                         dst_other.sha1, dst_other.mode,
                                                         branch1, branch2);
index c1c66bd408c50685c06fe7ff1e1c6a78c26be1b1..670bf09b452e5e74a76df17535ea53b133d26091 100644 (file)
@@ -3,6 +3,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "color.h"
+#include "utf8.h"
 
 static int parse_options_usage(struct parse_opt_ctx_t *ctx,
                               const char * const *usagestr,
@@ -491,7 +492,7 @@ static int usage_argh(const struct option *opts, FILE *outfile)
                        s = literal ? "[%s]" : "[<%s>]";
        else
                s = literal ? " %s" : " <%s>";
-       return fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
+       return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
 }
 
 #define USAGE_OPTS_WIDTH 24
@@ -550,7 +551,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
                if (opts->long_name)
                        pos += fprintf(outfile, "--%s", opts->long_name);
                if (opts->type == OPTION_NUMBER)
-                       pos += fprintf(outfile, "-NUM");
+                       pos += utf8_fprintf(outfile, _("-NUM"));
 
                if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) ||
                    !(opts->flags & PARSE_OPT_NOARG))
diff --git a/path.c b/path.c
index cbbdf7d6ba68160a3a9936976e53d773d181ceac..d3d3f8b8ad75b9817df3014296aabc34b6a4eb14 100644 (file)
--- a/path.c
+++ b/path.c
@@ -12,6 +12,7 @@
  */
 #include "cache.h"
 #include "strbuf.h"
+#include "string-list.h"
 
 static char bad_path[] = "/bad-path/";
 
@@ -569,43 +570,38 @@ int normalize_path_copy(char *dst, const char *src)
 
 /*
  * path = Canonical absolute path
- * prefix_list = Colon-separated list of absolute paths
+ * prefixes = string_list containing normalized, absolute paths without
+ * trailing slashes (except for the root directory, which is denoted by "/").
  *
- * Determines, for each path in prefix_list, whether the "prefix" really
+ * Determines, for each path in prefixes, whether the "prefix"
  * is an ancestor directory of path.  Returns the length of the longest
  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
- * is an ancestor.  (Note that this means 0 is returned if prefix_list is
- * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
+ * is an ancestor.  (Note that this means 0 is returned if prefixes is
+ * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
  * are not considered to be their own ancestors.  path must be in a
  * canonical form: empty components, or "." or ".." components are not
- * allowed.  prefix_list may be null, which is like "".
+ * allowed.
  */
-int longest_ancestor_length(const char *path, const char *prefix_list)
+int longest_ancestor_length(const char *path, struct string_list *prefixes)
 {
-       char buf[PATH_MAX+1];
-       const char *ceil, *colon;
-       int len, max_len = -1;
+       int i, max_len = -1;
 
-       if (prefix_list == NULL || !strcmp(path, "/"))
+       if (!strcmp(path, "/"))
                return -1;
 
-       for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
-               for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
-               len = colon - ceil;
-               if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
-                       continue;
-               strlcpy(buf, ceil, len+1);
-               if (normalize_path_copy(buf, buf) < 0)
-                       continue;
-               len = strlen(buf);
-               if (len > 0 && buf[len-1] == '/')
-                       buf[--len] = '\0';
+       for (i = 0; i < prefixes->nr; i++) {
+               const char *ceil = prefixes->items[i].string;
+               int len = strlen(ceil);
 
-               if (!strncmp(path, buf, len) &&
-                   path[len] == '/' &&
-                   len > max_len) {
+               if (len == 1 && ceil[0] == '/')
+                       len = 0; /* root matches anything, with length 0 */
+               else if (!strncmp(path, ceil, len) && path[len] == '/')
+                       ; /* match of length len */
+               else
+                       continue; /* no match */
+
+               if (len > max_len)
                        max_len = len;
-               }
        }
 
        return max_len;
index 497f420178a73061901393f8c21a9feb17054b6d..a56d1e76f797cdba83510a5488945425f1936c2d 100644 (file)
@@ -58,7 +58,8 @@ =head1 SYNOPSIS
                 command_output_pipe command_input_pipe command_close_pipe
                 command_bidi_pipe command_close_bidi_pipe
                 version exec_path html_path hash_object git_cmd_try
-                remote_refs
+                remote_refs prompt
+                get_tz_offset
                 temp_acquire temp_release temp_reset temp_path);
 
 
@@ -102,6 +103,7 @@ =head1 DESCRIPTION
 use Cwd qw(abs_path cwd);
 use IPC::Open2 qw(open2);
 use Fcntl qw(SEEK_SET SEEK_CUR);
+use Time::Local qw(timegm);
 }
 
 
@@ -512,6 +514,79 @@ sub version {
 sub html_path { command_oneline('--html-path') }
 
 
+=item get_tz_offset ( TIME )
+
+Return the time zone offset from GMT in the form +/-HHMM where HH is
+the number of hours from GMT and MM is the number of minutes.  This is
+the equivalent of what strftime("%z", ...) would provide on a GNU
+platform.
+
+If TIME is not supplied, the current local time is used.
+
+=cut
+
+sub get_tz_offset {
+       # some systmes don't handle or mishandle %z, so be creative.
+       my $t = shift || time;
+       my $gm = timegm(localtime($t));
+       my $sign = qw( + + - )[ $gm <=> $t ];
+       return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
+}
+
+
+=item prompt ( PROMPT , ISPASSWORD  )
+
+Query user C<PROMPT> and return answer from user.
+
+Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying
+the user. If no *_ASKPASS variable is set or an error occoured,
+the terminal is tried as a fallback.
+If C<ISPASSWORD> is set and true, the terminal disables echo.
+
+=cut
+
+sub prompt {
+       my ($prompt, $isPassword) = @_;
+       my $ret;
+       if (exists $ENV{'GIT_ASKPASS'}) {
+               $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt);
+       }
+       if (!defined $ret && exists $ENV{'SSH_ASKPASS'}) {
+               $ret = _prompt($ENV{'SSH_ASKPASS'}, $prompt);
+       }
+       if (!defined $ret) {
+               print STDERR $prompt;
+               STDERR->flush;
+               if (defined $isPassword && $isPassword) {
+                       require Term::ReadKey;
+                       Term::ReadKey::ReadMode('noecho');
+                       $ret = '';
+                       while (defined(my $key = Term::ReadKey::ReadKey(0))) {
+                               last if $key =~ /[\012\015]/; # \n\r
+                               $ret .= $key;
+                       }
+                       Term::ReadKey::ReadMode('restore');
+                       print STDERR "\n";
+                       STDERR->flush;
+               } else {
+                       chomp($ret = <STDIN>);
+               }
+       }
+       return $ret;
+}
+
+sub _prompt {
+       my ($askpass, $prompt) = @_;
+       return unless length $askpass;
+       $prompt =~ s/\n/ /g;
+       my $ret;
+       open my $fh, "-|", $askpass, $prompt or return;
+       $ret = <$fh>;
+       $ret =~ s/[\015\012]//g; # strip \r\n, chomp does not work on all systems (i.e. windows) as expected
+       close ($fh);
+       return $ret;
+}
+
 =item repo_path ()
 
 Return path to the git repository. Must be called on a repository instance.
index 59215fa86e2c2902ec97b12bea70736f9c7c02c6..8c84560a495203a47b77faac36e5661aeace5df0 100644 (file)
@@ -11,7 +11,6 @@ package Git::SVN;
 use File::Path qw/mkpath/;
 use File::Copy qw/copy/;
 use IPC::Open3;
-use Time::Local;
 use Memoize;  # core since 5.8.0, Jul 2002
 use Memoize::Storable;
 use POSIX qw(:signal_h);
@@ -22,6 +21,7 @@ package Git::SVN;
     command_noisy
     command_output_pipe
     command_close_pipe
+    get_tz_offset
 );
 use Git::SVN::Utils qw(
        fatal
@@ -1311,14 +1311,6 @@ sub get_untracked {
        \@out;
 }
 
-sub get_tz {
-       # some systmes don't handle or mishandle %z, so be creative.
-       my $t = shift || time;
-       my $gm = timelocal(gmtime($t));
-       my $sign = qw( + + - )[ $t <=> $gm ];
-       return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
-}
-
 # parse_svn_date(DATE)
 # --------------------
 # Given a date (in UTC) from Subversion, return a string in the format
@@ -1351,7 +1343,7 @@ sub parse_svn_date {
                        delete $ENV{TZ};
                }
 
-               my $our_TZ = get_tz();
+               my $our_TZ = get_tz_offset();
 
                # This converts $epoch_in_UTC into our local timezone.
                my ($sec, $min, $hour, $mday, $mon, $year,
index 3cc1c6f0817fe307390852c54a07cb2a07404f7e..3f8350a57d64ca3335d279c6563fad54b56eb22a 100644 (file)
@@ -2,7 +2,11 @@ package Git::SVN::Log;
 use strict;
 use warnings;
 use Git::SVN::Utils qw(fatal);
-use Git qw(command command_oneline command_output_pipe command_close_pipe);
+use Git qw(command
+           command_oneline
+           command_output_pipe
+           command_close_pipe
+           get_tz_offset);
 use POSIX qw/strftime/;
 use constant commit_log_separator => ('-' x 72) . "\n";
 use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
@@ -119,7 +123,7 @@ sub run_pager {
 sub format_svn_date {
        my $t = shift || time;
        require Git::SVN;
-       my $gmoff = Git::SVN::get_tz($t);
+       my $gmoff = get_tz_offset($t);
        return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
 }
 
index 3a6f8af0d9849c5f2fc886f8fc3ac9a8575e271e..74daa7a597fcf55a649a4e90367b1e783a74fcd5 100644 (file)
@@ -62,16 +62,16 @@ sub ssl_server_trust {
                                       issuer_dname fingerprint);
        my $choice;
 prompt:
-       print STDERR $may_save ?
+       my $options = $may_save ?
              "(R)eject, accept (t)emporarily or accept (p)ermanently? " :
              "(R)eject or accept (t)emporarily? ";
        STDERR->flush;
-       $choice = lc(substr(<STDIN> || 'R', 0, 1));
-       if ($choice =~ /^t$/i) {
+       $choice = lc(substr(Git::prompt("Certificate problem.\n" . $options) || 'R', 0, 1));
+       if ($choice eq 't') {
                $cred->may_save(undef);
-       } elsif ($choice =~ /^r$/i) {
+       } elsif ($choice eq 'r') {
                return -1;
-       } elsif ($may_save && $choice =~ /^p$/i) {
+       } elsif ($may_save && $choice eq 'p') {
                $cred->may_save($may_save);
        } else {
                goto prompt;
@@ -109,9 +109,7 @@ sub username {
        if (defined $_username) {
                $username = $_username;
        } else {
-               print STDERR "Username: ";
-               STDERR->flush;
-               chomp($username = <STDIN>);
+               $username = Git::prompt("Username: ");
        }
        $cred->username($username);
        $cred->may_save($may_save);
@@ -120,25 +118,7 @@ sub username {
 
 sub _read_password {
        my ($prompt, $realm) = @_;
-       my $password = '';
-       if (exists $ENV{GIT_ASKPASS}) {
-               open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt);
-               $password = <PH>;
-               $password =~ s/[\012\015]//; # \n\r
-               close(PH);
-       } else {
-               print STDERR $prompt;
-               STDERR->flush;
-               require Term::ReadKey;
-               Term::ReadKey::ReadMode('noecho');
-               while (defined(my $key = Term::ReadKey::ReadKey(0))) {
-                       last if $key =~ /[\012\015]/; # \n\r
-                       $password .= $key;
-               }
-               Term::ReadKey::ReadMode('restore');
-               print STDERR "\n";
-               STDERR->flush;
-       }
+       my $password = Git::prompt($prompt, 1);
        $password;
 }
 
index 5bdc2e70bcd1e8fc0c7e625c3eac26397d8c96d2..91bb2d3ef675b12ac5425ae71600e13c1adc34f9 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -567,7 +567,7 @@ char *logmsg_reencode(const struct commit *commit,
        char *encoding;
        char *out;
 
-       if (!*output_encoding)
+       if (!output_encoding || !*output_encoding)
                return NULL;
        encoding = get_header(commit, "encoding");
        use_encoding = encoding ? encoding : utf8;
@@ -1250,23 +1250,15 @@ void format_commit_message(const struct commit *commit,
                           const struct pretty_print_context *pretty_ctx)
 {
        struct format_commit_context context;
-       static const char utf8[] = "UTF-8";
        const char *output_enc = pretty_ctx->output_encoding;
 
        memset(&context, 0, sizeof(context));
        context.commit = commit;
        context.pretty_ctx = pretty_ctx;
        context.wrap_start = sb->len;
-       context.message = commit->buffer;
-       if (output_enc) {
-               char *enc = get_header(commit, "encoding");
-               if (strcmp(enc ? enc : utf8, output_enc)) {
-                       context.message = logmsg_reencode(commit, output_enc);
-                       if (!context.message)
-                               context.message = commit->buffer;
-               }
-               free(enc);
-       }
+       context.message = logmsg_reencode(commit, output_enc);
+       if (!context.message)
+               context.message = commit->buffer;
 
        strbuf_expand(sb, format, format_commit_item, &context);
        rewrap_message_tail(sb, &context, 0, 0, 0);
diff --git a/refs.c b/refs.c
index 6cec1c8bdf70589a41c2ace4ba4f21f4035e4ed4..541fec20658082f13ef4b73b621787512b300ba6 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1744,7 +1744,8 @@ static struct lock_file packlock;
 static int repack_without_ref(const char *refname)
 {
        struct repack_without_ref_sb data;
-       struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL));
+       struct ref_cache *refs = get_ref_cache(NULL);
+       struct ref_dir *packed = get_packed_refs(refs);
        if (find_ref(packed, refname) == NULL)
                return 0;
        data.refname = refname;
@@ -1753,6 +1754,8 @@ static int repack_without_ref(const char *refname)
                unable_to_lock_error(git_path("packed-refs"), errno);
                return error("cannot delete '%s' from packed refs", refname);
        }
+       clear_packed_ref_cache(refs);
+       packed = get_packed_refs(refs);
        do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data);
        return commit_lock_file(&packlock);
 }
index 9a8b12350712422e660f40fdf5ef9f191d37de99..933c69ac2627c1903276b92b457843e12649f39e 100644 (file)
@@ -92,6 +92,8 @@ static void free_discovery(struct discovery *d)
 
 static struct discovery* discover_refs(const char *service)
 {
+       struct strbuf exp = STRBUF_INIT;
+       struct strbuf type = STRBUF_INIT;
        struct strbuf buffer = STRBUF_INIT;
        struct discovery *last = last_discovery;
        char *refs_url;
@@ -113,7 +115,7 @@ static struct discovery* discover_refs(const char *service)
        }
        refs_url = strbuf_detach(&buffer, NULL);
 
-       http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
+       http_ret = http_get_strbuf(refs_url, &type, &buffer, HTTP_NO_CACHE);
        switch (http_ret) {
        case HTTP_OK:
                break;
@@ -132,17 +134,20 @@ static struct discovery* discover_refs(const char *service)
        last->buf_alloc = strbuf_detach(&buffer, &last->len);
        last->buf = last->buf_alloc;
 
-       if (maybe_smart && 5 <= last->len && last->buf[4] == '#') {
-               /* smart HTTP response; validate that the service
+       strbuf_addf(&exp, "application/x-%s-advertisement", service);
+       if (maybe_smart &&
+           (5 <= last->len && last->buf[4] == '#') &&
+           !strbuf_cmp(&exp, &type)) {
+               /*
+                * smart HTTP response; validate that the service
                 * pkt-line matches our request.
                 */
-               struct strbuf exp = STRBUF_INIT;
-
                if (packet_get_line(&buffer, &last->buf, &last->len) <= 0)
                        die("%s has invalid packet header", refs_url);
                if (buffer.len && buffer.buf[buffer.len - 1] == '\n')
                        strbuf_setlen(&buffer, buffer.len - 1);
 
+               strbuf_reset(&exp);
                strbuf_addf(&exp, "# service=%s", service);
                if (strbuf_cmp(&exp, &buffer))
                        die("invalid server response; got '%s'", buffer.buf);
@@ -160,6 +165,8 @@ static struct discovery* discover_refs(const char *service)
        }
 
        free(refs_url);
+       strbuf_release(&exp);
+       strbuf_release(&type);
        strbuf_release(&buffer);
        last_discovery = last;
        return last;
index 6aa49c03df13245486b20b04315437811b260882..ca1f8f2eafbef40046f2890501ad757bde9585f1 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1370,6 +1370,16 @@ int branch_merge_matches(struct branch *branch,
        return refname_match(branch->merge[i]->src, refname, ref_fetch_rules);
 }
 
+static int ignore_symref_update(const char *refname)
+{
+       unsigned char sha1[20];
+       int flag;
+
+       if (!resolve_ref_unsafe(refname, sha1, 0, &flag))
+               return 0; /* non-existing refs are OK */
+       return (flag & REF_ISSYMREF);
+}
+
 static struct ref *get_expanded_map(const struct ref *remote_refs,
                                    const struct refspec *refspec)
 {
@@ -1383,7 +1393,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
                if (strchr(ref->name, '^'))
                        continue; /* a dereference item */
                if (match_name_with_pattern(refspec->src, ref->name,
-                                           refspec->dst, &expn_name)) {
+                                           refspec->dst, &expn_name) &&
+                   !ignore_symref_update(expn_name)) {
                        struct ref *cpy = copy_ref(ref);
 
                        cpy->peer_ref = alloc_ref(expn_name);
index 3b982e4d55274ebe87c5751fa198bee53e371d9b..04712191e8acfbf000c526a5b1b0a80541e8e174 100644 (file)
@@ -226,7 +226,7 @@ static inline void set_cloexec(int fd)
                fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
 }
 
-static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
+static int wait_or_whine(pid_t pid, const char *argv0)
 {
        int status, code = -1;
        pid_t waiting;
@@ -242,13 +242,14 @@ static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
                error("waitpid is confused (%s)", argv0);
        } else if (WIFSIGNALED(status)) {
                code = WTERMSIG(status);
-               error("%s died of signal %d", argv0, code);
+               if (code != SIGINT && code != SIGQUIT)
+                       error("%s died of signal %d", argv0, code);
                /*
                 * This return value is chosen so that code & 0xff
                 * mimics the exit code that a POSIX shell would report for
                 * a program that died from this signal.
                 */
-               code -= 128;
+               code += 128;
        } else if (WIFEXITED(status)) {
                code = WEXITSTATUS(status);
                /*
@@ -432,8 +433,7 @@ int start_command(struct child_process *cmd)
                 * At this point we know that fork() succeeded, but execvp()
                 * failed. Errors have been reported to our stderr.
                 */
-               wait_or_whine(cmd->pid, cmd->argv[0],
-                             cmd->silent_exec_failure);
+               wait_or_whine(cmd->pid, cmd->argv[0]);
                failed_errno = errno;
                cmd->pid = -1;
        }
@@ -538,7 +538,7 @@ int start_command(struct child_process *cmd)
 
 int finish_command(struct child_process *cmd)
 {
-       return wait_or_whine(cmd->pid, cmd->argv[0], cmd->silent_exec_failure);
+       return wait_or_whine(cmd->pid, cmd->argv[0]);
 }
 
 int run_command(struct child_process *cmd)
@@ -725,7 +725,7 @@ int start_async(struct async *async)
 int finish_async(struct async *async)
 {
 #ifdef NO_PTHREADS
-       return wait_or_whine(async->pid, "child process", 0);
+       return wait_or_whine(async->pid, "child process");
 #else
        void *ret = (void *)(intptr_t)(-1);
 
index 22604902aa4c4dd146f562c4841c344a773a9bda..aef5e8a0170c5b337f1aa3ac7a35be3b54957729 100644 (file)
@@ -186,14 +186,15 @@ static int error_dirty_index(struct replay_opts *opts)
        return -1;
 }
 
-static int fast_forward_to(const unsigned char *to, const unsigned char *from)
+static int fast_forward_to(const unsigned char *to, const unsigned char *from,
+                          int unborn)
 {
        struct ref_lock *ref_lock;
 
        read_cache();
        if (checkout_fast_forward(from, to, 1))
                exit(1); /* the callee should have complained already */
-       ref_lock = lock_any_ref_for_update("HEAD", from, 0);
+       ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from, 0);
        return write_ref_sha1(ref_lock, to, "cherry-pick");
 }
 
@@ -390,7 +391,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
        struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
        char *defmsg = NULL;
        struct strbuf msgbuf = STRBUF_INIT;
-       int res;
+       int res, unborn = 0;
 
        if (opts->no_commit) {
                /*
@@ -402,9 +403,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
                if (write_cache_as_tree(head, 0, NULL))
                        die (_("Your index file is unmerged."));
        } else {
-               if (get_sha1("HEAD", head))
-                       return error(_("You do not have a valid HEAD"));
-               if (index_differs_from("HEAD", 0))
+               unborn = get_sha1("HEAD", head);
+               if (unborn)
+                       hashcpy(head, EMPTY_TREE_SHA1_BIN);
+               if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0))
                        return error_dirty_index(opts);
        }
        discard_cache();
@@ -435,8 +437,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
        else
                parent = commit->parents->item;
 
-       if (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))
-               return fast_forward_to(commit->object.sha1, head);
+       if (opts->allow_ff &&
+           ((parent && !hashcmp(parent->object.sha1, head)) ||
+            (!parent && unborn)))
+            return fast_forward_to(commit->object.sha1, head, unborn);
 
        if (parent && parse_commit(parent) < 0)
                /* TRANSLATORS: The first %s will be "revert" or
diff --git a/setup.c b/setup.c
index 3a1b2fd45580cad7ecd55efa755872efc81075ad..f108c4b990c0e4f6a98c1fe34d3031040c84195a 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "dir.h"
+#include "string-list.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -620,6 +621,27 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
        return buf.st_dev;
 }
 
+/*
+ * A "string_list_each_func_t" function that canonicalizes an entry
+ * from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
+ * discards it if unusable.
+ */
+static int canonicalize_ceiling_entry(struct string_list_item *item,
+                                     void *unused)
+{
+       char *ceil = item->string;
+       const char *real_path;
+
+       if (!*ceil || !is_absolute_path(ceil))
+               return 0;
+       real_path = real_path_if_valid(ceil);
+       if (!real_path)
+               return 0;
+       free(item->string);
+       item->string = xstrdup(real_path);
+       return 1;
+}
+
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
@@ -627,10 +649,11 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
 static const char *setup_git_directory_gently_1(int *nongit_ok)
 {
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
+       struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
        static char cwd[PATH_MAX+1];
        const char *gitdirenv, *ret;
        char *gitfile;
-       int len, offset, offset_parent, ceil_offset;
+       int len, offset, offset_parent, ceil_offset = -1;
        dev_t current_device = 0;
        int one_filesystem = 1;
 
@@ -655,7 +678,14 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        if (gitdirenv)
                return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
 
-       ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
+       if (env_ceiling_dirs) {
+               string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
+               filter_string_list(&ceiling_dirs, 0,
+                                  canonicalize_ceiling_entry, NULL);
+               ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
+               string_list_clear(&ceiling_dirs, 0);
+       }
+
        if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
                ceil_offset = 1;
 
index 397e6cfa7db82bdb17f7cdbe4662a1607c0773af..480173fe6dbee5428e3b135ff27ba7551c527ad8 100644 (file)
@@ -145,26 +145,6 @@ void string_list_remove_empty_items(struct string_list *list, int free_util) {
        filter_string_list(list, free_util, item_is_not_empty, NULL);
 }
 
-char *string_list_longest_prefix(const struct string_list *prefixes,
-                                const char *string)
-{
-       int i, max_len = -1;
-       char *retval = NULL;
-
-       for (i = 0; i < prefixes->nr; i++) {
-               char *prefix = prefixes->items[i].string;
-               if (!prefixcmp(string, prefix)) {
-                       int len = strlen(prefix);
-                       if (len > max_len) {
-                               retval = prefix;
-                               max_len = len;
-                       }
-               }
-       }
-
-       return retval;
-}
-
 void string_list_clear(struct string_list *list, int free_util)
 {
        if (list->items) {
index c50b0d0deac086cd5a50a5c021103a5f5e76c1cd..db1284861adb707b675714edc1ecacf9357f6661 100644 (file)
@@ -45,15 +45,6 @@ void filter_string_list(struct string_list *list, int free_util,
  */
 void string_list_remove_empty_items(struct string_list *list, int free_util);
 
-/*
- * Return the longest string in prefixes that is a prefix (in the
- * sense of prefixcmp()) of string, or NULL if no such prefix exists.
- * This function does not require the string_list to be sorted (it
- * does a linear search).
- */
-char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
-
-
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
 int string_list_find_insert_index(const struct string_list *list, const char *string,
index 3025418ff57c8c16cd11dd0db4f9d442743118fa..5c6de8169bfc02fc280d2dcb8cf34a912f0b0f6a 100644 (file)
@@ -13,6 +13,7 @@ TAR ?= $(TAR)
 RM ?= rm -f
 PROVE ?= prove
 DEFAULT_TEST_TARGET ?= test
+TEST_LINT ?= test-lint-duplicates test-lint-executable
 
 # Shell quote;
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
index 0f76f6cdc06b88c3e099c64cab76bfe7a019f8db..ae8883a07514c47b0568c9323698e879b38703e5 100644 (file)
@@ -14,12 +14,14 @@ export GIT_TEXTDOMAINDIR GIT_PO_PATH
 if test_have_prereq GETTEXT && ! test_have_prereq GETTEXT_POISON
 then
        # is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian
-       is_IS_locale=$(locale -a | sed -n '/^is_IS\.[uU][tT][fF]-*8$/{
+       is_IS_locale=$(locale -a 2>/dev/null |
+               sed -n '/^is_IS\.[uU][tT][fF]-*8$/{
                p
                q
        }')
        # is_IS.ISO8859-1 on Solaris and FreeBSD, is_IS.iso88591 on Debian
-       is_IS_iso_locale=$(locale -a | sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{
+       is_IS_iso_locale=$(locale -a 2>/dev/null |
+               sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{
                p
                q
        }')
index 02f442bfadbb1239785a456cddc50223da4f3834..895b9258b07ca65b78ac376023e203f482d8ac16 100644 (file)
@@ -80,6 +80,7 @@ fi
 prepare_httpd() {
        mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH"
        cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
+       cp "$TEST_PATH"/broken-smart-http.sh "$HTTPD_ROOT_PATH"
 
        ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
 
index fe76e84b74472a431eef59a1f4936cfc69367003..938b4cf803b3b4ea07be20338425f784b80cdf0c 100644 (file)
@@ -62,9 +62,13 @@ Alias /auth/dumb/ www/auth/dumb/
        SetEnv GIT_COMMITTER_EMAIL custom@example.com
 </LocationMatch>
 ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
+ScriptAlias /broken_smart/ broken-smart-http.sh/
 <Directory ${GIT_EXEC_PATH}>
        Options FollowSymlinks
 </Directory>
+<Files broken-smart-http.sh>
+       Options ExecCGI
+</Files>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
        Options ExecCGI
 </Files>
diff --git a/t/lib-httpd/broken-smart-http.sh b/t/lib-httpd/broken-smart-http.sh
new file mode 100755 (executable)
index 0000000..f7ebfff
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+printf "Content-Type: text/%s\n" "html"
+echo
+printf "%s\n" "001e# service=git-upload-pack"
+printf "%s"   "0000"
+printf "%s%c%s%s\n" \
+       "00a58681d9f286a48b08f37b3a095330da16689e3693 HEAD" \
+       0 \
+       " include-tag multi_ack_detailed multi_ack ofs-delta" \
+       " side-band side-band-64k thin-pack no-progress shallow no-done "
+printf "%s"   "0000"
index ec6c1b3f8a7eac0e1734883a0ad2f2d68f11bf96..5378787e1b23bf18796c28c33533f677b389289c 100755 (executable)
@@ -3,7 +3,12 @@
 test_description='respect crlf in git archive'
 
 . ./test-lib.sh
-UNZIP=${UNZIP:-unzip}
+GIT_UNZIP=${GIT_UNZIP:-unzip}
+
+test_lazy_prereq UNZIP '
+       "$GIT_UNZIP" -v
+       test $? -ne 127
+'
 
 test_expect_success setup '
 
@@ -26,18 +31,11 @@ test_expect_success 'tar archive' '
 
 '
 
-"$UNZIP" -v >/dev/null 2>&1
-if [ $? -eq 127 ]; then
-       say "Skipping ZIP test, because unzip was not found"
-else
-       test_set_prereq UNZIP
-fi
-
 test_expect_success UNZIP 'zip archive' '
 
        git archive --format=zip HEAD >test.zip &&
 
-       ( mkdir unzipped && cd unzipped && unzip ../test.zip ) &&
+       ( mkdir unzipped && cd unzipped && "$GIT_UNZIP" ../test.zip ) &&
 
        test_cmp sample unzipped/sample
 
index 78816d9d935df478f5cdf93e06fae26cc5488910..05d78d22a6d0fa5534ae3f37cb3c289595b6c1c5 100755 (executable)
@@ -29,12 +29,10 @@ test_have_prereq SYMLINKS ||
 if test_have_prereq CASE_INSENSITIVE_FS
 then
 test_expect_success "detection of case insensitive filesystem during repo init" '
-
        test $(git config --bool core.ignorecase) = true
 '
 else
 test_expect_success "detection of case insensitive filesystem during repo init" '
-
        test_must_fail git config --bool core.ignorecase >/dev/null ||
        test $(git config --bool core.ignorecase) = false
 '
@@ -43,20 +41,17 @@ fi
 if test_have_prereq SYMLINKS
 then
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
-
        test_must_fail git config --bool core.symlinks ||
        test "$(git config --bool core.symlinks)" = true
 '
 else
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
-
        v=$(git config --bool core.symlinks) &&
        test "$v" = false
 '
 fi
 
 test_expect_success "setup case tests" '
-
        git config core.ignorecase true &&
        touch camelcase &&
        git add camelcase &&
@@ -67,29 +62,23 @@ test_expect_success "setup case tests" '
        git mv tmp CamelCase &&
        git commit -m "rename" &&
        git checkout -f master
-
 '
 
 $test_case 'rename (case change)' '
-
        git mv camelcase CamelCase &&
        git commit -m "rename"
-
 '
 
-$test_case 'merge (case change)' '
-
+test_expect_success 'merge (case change)' '
        rm -f CamelCase &&
        rm -f camelcase &&
        git reset --hard initial &&
        git merge topic
-
 '
 
 
 
-test_expect_failure 'add (with different case)' '
-
+test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
        git reset --hard initial &&
        rm camelcase &&
        echo 1 >CamelCase &&
@@ -97,37 +86,30 @@ test_expect_failure 'add (with different case)' '
        camel=$(git ls-files | grep -i camelcase) &&
        test $(echo "$camel" | wc -l) = 1 &&
        test "z$(git cat-file blob :$camel)" = z1
-
 '
 
 test_expect_success "setup unicode normalization tests" '
-
-  test_create_repo unicode &&
-  cd unicode &&
-  touch "$aumlcdiar" &&
-  git add "$aumlcdiar" &&
-  git commit -m initial &&
-  git tag initial &&
-  git checkout -b topic &&
-  git mv $aumlcdiar tmp &&
-  git mv tmp "$auml" &&
-  git commit -m rename &&
-  git checkout -f master
-
+       test_create_repo unicode &&
+       cd unicode &&
+       touch "$aumlcdiar" &&
+       git add "$aumlcdiar" &&
+       git commit -m initial &&
+       git tag initial &&
+       git checkout -b topic &&
+       git mv $aumlcdiar tmp &&
+       git mv tmp "$auml" &&
+       git commit -m rename &&
+       git checkout -f master
 '
 
 $test_unicode 'rename (silent unicode normalization)' '
-
- git mv "$aumlcdiar" "$auml" &&
- git commit -m rename
-
+       git mv "$aumlcdiar" "$auml" &&
+       git commit -m rename
 '
 
 $test_unicode 'merge (silent unicode normalization)' '
-
- git reset --hard initial &&
- git merge topic
-
+       git reset --hard initial &&
+       git merge topic
 '
 
 test_done
index 4ef2345982fe0e0c175ed67edcb20b04c81b9680..09a42a428e1d286c5ab9e1003d49481ef6df3e44 100755 (executable)
@@ -93,47 +93,32 @@ norm_path /d1/s1//../s2/../../d2 /d2 POSIX
 norm_path /d1/.../d2 /d1/.../d2 POSIX
 norm_path /d1/..././../d2 /d1/d2 POSIX
 
-ancestor / "" -1
 ancestor / / -1
-ancestor /foo "" -1
-ancestor /foo : -1
-ancestor /foo ::. -1
-ancestor /foo ::..:: -1
 ancestor /foo / 0
 ancestor /foo /fo -1
 ancestor /foo /foo -1
-ancestor /foo /foo/ -1
 ancestor /foo /bar -1
-ancestor /foo /bar/ -1
 ancestor /foo /foo/bar -1
-ancestor /foo /foo:/bar/ -1
-ancestor /foo /foo/:/bar/ -1
-ancestor /foo /foo::/bar/ -1
-ancestor /foo /:/foo:/bar/ 0
-ancestor /foo /foo:/:/bar/ 0
-ancestor /foo /:/bar/:/foo 0
-ancestor /foo/bar "" -1
+ancestor /foo /foo:/bar -1
+ancestor /foo /:/foo:/bar 0
+ancestor /foo /foo:/:/bar 0
+ancestor /foo /:/bar:/foo 0
 ancestor /foo/bar / 0
 ancestor /foo/bar /fo -1
-ancestor /foo/bar foo -1
 ancestor /foo/bar /foo 4
-ancestor /foo/bar /foo/ 4
 ancestor /foo/bar /foo/ba -1
 ancestor /foo/bar /:/fo 0
 ancestor /foo/bar /foo:/foo/ba 4
 ancestor /foo/bar /bar -1
-ancestor /foo/bar /bar/ -1
-ancestor /foo/bar /fo: -1
-ancestor /foo/bar :/fo -1
-ancestor /foo/bar /foo:/bar/ 4
-ancestor /foo/bar /:/foo:/bar/ 4
-ancestor /foo/bar /foo:/:/bar/ 4
-ancestor /foo/bar /:/bar/:/fo 0
-ancestor /foo/bar /:/bar/ 0
-ancestor /foo/bar .:/foo/. 4
-ancestor /foo/bar .:/foo/.:.: 4
-ancestor /foo/bar /foo/./:.:/bar 4
-ancestor /foo/bar .:/bar -1
+ancestor /foo/bar /fo -1
+ancestor /foo/bar /foo:/bar 4
+ancestor /foo/bar /:/foo:/bar 4
+ancestor /foo/bar /foo:/:/bar 4
+ancestor /foo/bar /:/bar:/fo 0
+ancestor /foo/bar /:/bar 0
+ancestor /foo/bar /foo 4
+ancestor /foo/bar /foo:/bar 4
+ancestor /foo/bar /bar -1
 
 test_expect_success 'strip_path_suffix' '
        test c:/msysgit = $(test-path-utils strip_path_suffix \
index 41c8826a74db9a5c34ad3365f4875f6317a5bca0..dbfc05ebdc3990bf4ea5b0163afb4c6a9e698fa7 100755 (executable)
@@ -17,14 +17,6 @@ test_split () {
        "
 }
 
-test_longest_prefix () {
-       test "$(test-string-list longest_prefix "$1" "$2")" = "$3"
-}
-
-test_no_longest_prefix () {
-       test_must_fail test-string-list longest_prefix "$1" "$2"
-}
-
 test_split "foo:bar:baz" ":" "-1" <<EOF
 3
 [0]: "foo"
@@ -96,26 +88,4 @@ test_expect_success "test remove_duplicates" '
        test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)"
 '
 
-test_expect_success "test longest_prefix" '
-       test_no_longest_prefix - '' &&
-       test_no_longest_prefix - x &&
-       test_longest_prefix "" x "" &&
-       test_longest_prefix x x x &&
-       test_longest_prefix "" foo "" &&
-       test_longest_prefix : foo "" &&
-       test_longest_prefix f foo f &&
-       test_longest_prefix foo foobar foo &&
-       test_longest_prefix foo foo foo &&
-       test_no_longest_prefix bar foo &&
-       test_no_longest_prefix bar:bar foo &&
-       test_no_longest_prefix foobar foo &&
-       test_longest_prefix foo:bar foo foo &&
-       test_longest_prefix foo:bar bar bar &&
-       test_longest_prefix foo::bar foo foo &&
-       test_longest_prefix foo:foobar foo foo &&
-       test_longest_prefix foobar:foo foo foo &&
-       test_longest_prefix foo: bar "" &&
-       test_longest_prefix :foo bar ""
-'
-
 test_done
index e23ac0e69da8d3dba32f0d256a249a987356e825..1e2945ec7e397cf6b2e3b00bee0ca1df40a0e6a9 100755 (executable)
@@ -111,19 +111,19 @@ test_expect_success 'read-tree' '
 
 test_expect_success 'alias expansion' '
        (
-               git config alias.ss status &&
+               git config alias.test-status-alias status &&
                cd dir &&
                git status &&
-               git ss
+               git test-status-alias
        )
 '
 
 test_expect_success NOT_MINGW '!alias expansion' '
        pwd >expect &&
        (
-               git config alias.test !pwd &&
+               git config alias.test-alias-directory !pwd &&
                cd dir &&
-               git test >../actual
+               git test-alias-directory >../actual
        ) &&
        test_cmp expect actual
 '
@@ -131,9 +131,9 @@ test_expect_success NOT_MINGW '!alias expansion' '
 test_expect_success 'GIT_PREFIX for !alias' '
        printf "dir/" >expect &&
        (
-               git config alias.test "!sh -c \"printf \$GIT_PREFIX\"" &&
+               git config alias.test-alias-directory "!sh -c \"printf \$GIT_PREFIX\"" &&
                cd dir &&
-               git test >../actual
+               git test-alias-directory >../actual
        ) &&
        test_cmp expect actual
 '
index 1ae4d87c929ec55a66d44bb23aecea8a2aea4346..1a5a5f39fd94f9eb98824b3d84983782b9ff71bb 100755 (executable)
@@ -11,7 +11,8 @@ valid_ref() {
                prereq=$1
                shift
        esac
-       test_expect_success $prereq "ref name '$1' is valid${2:+ with options $2}" "
+       desc="ref name '$1' is valid${2:+ with options $2}"
+       test_expect_success $prereq "$desc" "
                git check-ref-format $2 '$1'
        "
 }
@@ -22,7 +23,8 @@ invalid_ref() {
                prereq=$1
                shift
        esac
-       test_expect_success $prereq "ref name '$1' is invalid${2:+ with options $2}" "
+       desc="ref name '$1' is invalid${2:+ with options $2}"
+       test_expect_success $prereq "$desc" "
                test_must_fail git check-ref-format $2 '$1'
        "
 }
index d709ecf8df136539a746ef1873821baee6fab428..4969edb31441c81cf2e63385d07d780a52faa53b 100755 (executable)
@@ -32,32 +32,24 @@ test_expect_success 'setup' '
 #
 # and 'side' should be the last branch
 
-test_rev_equivalent () {
-
-       git rev-parse "$1" > expect &&
-       git rev-parse "$2" > output &&
-       test_cmp expect output
-
-}
-
 test_expect_success '@{-1} works' '
-       test_rev_equivalent side @{-1}
+       test_cmp_rev side @{-1}
 '
 
 test_expect_success '@{-1}~2 works' '
-       test_rev_equivalent side~2 @{-1}~2
+       test_cmp_rev side~2 @{-1}~2
 '
 
 test_expect_success '@{-1}^2 works' '
-       test_rev_equivalent side^2 @{-1}^2
+       test_cmp_rev side^2 @{-1}^2
 '
 
 test_expect_success '@{-1}@{1} works' '
-       test_rev_equivalent side@{1} @{-1}@{1}
+       test_cmp_rev side@{1} @{-1}@{1}
 '
 
 test_expect_success '@{-2} works' '
-       test_rev_equivalent master @{-2}
+       test_cmp_rev master @{-2}
 '
 
 test_expect_success '@{-3} fails' '
index ec35409f9cbe9bcdd3d21a6a5a15996b165d2fff..2a4a749b4fa3b07963a18b645d29ef774c01bbd1 100755 (executable)
@@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' '
        git commit -a -m all
 '
 
+test_expect_success 'cache-tree invalidates i-t-a paths' '
+       git reset --hard &&
+       mkdir dir &&
+       : >dir/foo &&
+       git add dir/foo &&
+       git commit -m foo &&
+
+       : >dir/bar &&
+       git add -N dir/bar &&
+       git diff --cached --name-only >actual &&
+       echo dir/bar >expect &&
+       test_cmp expect actual &&
+
+       git write-tree >/dev/null &&
+
+       git diff --cached --name-only >actual &&
+       echo dir/bar >expect &&
+       test_cmp expect actual
+'
+
 test_done
 
index 32fdc9938e1dc29d9a1c6c1dd54379ee33644561..8462be1db6a0fe4f9e28cd1662be604196141055 100755 (executable)
@@ -29,12 +29,6 @@ Initial setup:
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
-test_cmp_rev () {
-       git rev-parse --verify "$1" >expect.rev &&
-       git rev-parse --verify "$2" >actual.rev &&
-       test_cmp expect.rev actual.rev
-}
-
 set_fake_editor
 
 # WARNING: Modifications to the initial repository can change the SHA ID used
index 34c86e5de69468fe7618383e556d1711cc49b0bb..6f489e20eecb48c6e1a2dc2b1fe90e47e7b3e7ad 100755 (executable)
@@ -100,4 +100,13 @@ test_expect_success 'revert forbidden on dirty working tree' '
 
 '
 
+test_expect_success 'chery-pick on unborn branch' '
+       git checkout --orphan unborn &&
+       git rm --cached -r . &&
+       rm -rf * &&
+       git cherry-pick initial &&
+       git diff --quiet initial &&
+       ! test_cmp_rev initial HEAD
+'
+
 test_done
index 51ca391e472441d2d503e721795d609bfaad1100..373aad623c8f02f6f9753eb38c6393a69c027001 100755 (executable)
@@ -105,4 +105,12 @@ test_expect_success 'cherry pick a root commit with --ff' '
        test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
 '
 
+test_expect_success 'chery-pick --ff on unborn branch' '
+       git checkout --orphan unborn &&
+       git rm --cached -r . &&
+       rm -rf * &&
+       git cherry-pick --ff first &&
+       test_cmp_rev first HEAD
+'
+
 test_done
index c82f7210c4ca10e35d9d2000aa8da2d10194a6c6..223b98433c502b03c4ba70550cb32d42a5f6295b 100755 (executable)
@@ -11,12 +11,6 @@ test_description='test cherry-pick and revert with conflicts
 
 . ./test-lib.sh
 
-test_cmp_rev () {
-       git rev-parse --verify "$1" >expect.rev &&
-       git rev-parse --verify "$2" >actual.rev &&
-       test_cmp expect.rev actual.rev
-}
-
 pristine_detach () {
        git checkout -f "$1^0" &&
        git read-tree -u --reset HEAD &&
index 340afc760de030879fff496dca3db8432a6b992b..4e7136b83775946a07678119c7c9897bb0f2b709 100755 (executable)
@@ -5,15 +5,11 @@ test_description='test cherry-picking many commits'
 . ./test-lib.sh
 
 check_head_differs_from() {
-       head=$(git rev-parse --verify HEAD) &&
-       arg=$(git rev-parse --verify "$1") &&
-       test "$head" != "$arg"
+       ! test_cmp_rev HEAD "$1"
 }
 
 check_head_equals() {
-       head=$(git rev-parse --verify HEAD) &&
-       arg=$(git rev-parse --verify "$1") &&
-       test "$head" = "$arg"
+       test_cmp_rev HEAD "$1"
 }
 
 test_expect_success setup '
index b5fb527b2e686d158a6e7d53d6246b9e66f80a7b..7b7a89dbd5ce578e0a722345a00f247e383689ef 100755 (executable)
@@ -24,12 +24,6 @@ pristine_detach () {
        git clean -d -f -f -q -x
 }
 
-test_cmp_rev () {
-       git rev-parse --verify "$1" >expect.rev &&
-       git rev-parse --verify "$2" >actual.rev &&
-       test_cmp expect.rev actual.rev
-}
-
 test_expect_success setup '
        git config advice.detachedhead false &&
        echo unrelated >unrelated &&
index 06f63848eab384ae33eacd1fb46d5dc048143721..37bf5f13b07a632cb8e96e865a75b51f1b7844aa 100755 (executable)
@@ -474,7 +474,7 @@ test_expect_success 'rm of a conflicted populated submodule with a .git director
        git submodule update &&
        (cd submod &&
                rm .git &&
-               cp -a ../.git/modules/sub .git &&
+               cp -R ../.git/modules/sub .git &&
                GIT_WORK_TREE=. git config --unset core.worktree
        ) &&
        test_must_fail git merge conflict2 &&
@@ -508,7 +508,7 @@ test_expect_success 'rm of a populated submodule with a .git directory fails eve
        git submodule update &&
        (cd submod &&
                rm .git &&
-               cp -a ../.git/modules/sub .git &&
+               cp -R ../.git/modules/sub .git &&
                GIT_WORK_TREE=. git config --unset core.worktree
        ) &&
        test_must_fail git rm submod &&
@@ -606,7 +606,7 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc
        git submodule update --recursive &&
        (cd submod/subsubmod &&
                rm .git &&
-               cp -a ../../.git/modules/sub/modules/sub .git &&
+               cp -R ../../.git/modules/sub/modules/sub .git &&
                GIT_WORK_TREE=. git config --unset core.worktree
        ) &&
        test_must_fail git rm submod &&
index 16a4ca1d6061122cf7ed3abd68390e27794f79b0..90fd598c747482354c7fa1a9fa281c26c06e9de8 100755 (executable)
@@ -155,7 +155,7 @@ test_expect_failure 'additional command line cc (rfc822)' '
        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
-       grep "^ *"S. E. Cipient" <scipient@example.com>\$" patch5
+       grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5
 '
 
 test_expect_success 'command line headers' '
@@ -183,7 +183,7 @@ test_expect_success 'command line To: header (ascii)' '
 test_expect_failure 'command line To: header (rfc822)' '
 
        git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
-       grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch8
+       grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8
 '
 
 test_expect_failure 'command line To: header (rfc2047)' '
@@ -203,7 +203,7 @@ test_expect_failure 'configuration To: header (rfc822)' '
 
        git config format.to "R. E. Cipient <rcipient@example.com>" &&
        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
-       grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch9
+       grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9
 '
 
 test_expect_failure 'configuration To: header (rfc2047)' '
index 40277c77aad5f2d9533e6822da3380bb49621e59..614425adac536d84e6835d9d707b86fe8f5f4d36 100755 (executable)
@@ -89,4 +89,28 @@ test_expect_success 'diagnose truncated file' '
        grep "diff --cc file" out
 '
 
+test_expect_success 'setup for --cc --raw' '
+       blob=$(echo file | git hash-object --stdin -w) &&
+       base_tree=$(echo "100644 blob $blob     file" | git mktree) &&
+       trees= &&
+       for i in `test_seq 1 40`
+       do
+               blob=$(echo file$i | git hash-object --stdin -w) &&
+               trees="$trees$(echo "100644 blob $blob  file" | git mktree)$LF"
+       done
+'
+
+test_expect_success 'check --cc --raw with four trees' '
+       four_trees=$(echo "$trees" | sed -e 4q) &&
+       git diff --cc --raw $four_trees $base_tree >out &&
+       # Check for four leading colons in the output:
+       grep "^::::[^:]" out
+'
+
+test_expect_success 'check --cc --raw with forty trees' '
+       git diff --cc --raw $trees $base_tree >out &&
+       # Check for forty leading colons in the output:
+       grep "^::::::::::::::::::::::::::::::::::::::::[^:]" out
+'
+
 test_done
index 6872ba1a42ce289c0983b1ed62f05defb493bf49..5493500ef15d2f561bd14ca0bdf5f519ec6f49be 100755 (executable)
@@ -120,6 +120,30 @@ test_expect_success 'shortlog from non-git directory' '
        test_cmp expect out
 '
 
+test_expect_success 'shortlog should add newline when input line matches wraplen' '
+       cat >expect <<\EOF &&
+A U Thor (2):
+      bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb
+      aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa
+
+EOF
+       git shortlog -w >out <<\EOF &&
+commit 0000000000000000000000000000000000000001
+Author: A U Thor <author@example.com>
+Date:   Thu Apr 7 15:14:13 2005 -0700
+
+    aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa
+
+commit 0000000000000000000000000000000000000002
+Author: A U Thor <author@example.com>
+Date:   Thu Apr 7 15:14:13 2005 -0700
+
+    bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb
+
+EOF
+       test_cmp expect out
+'
+
 iconvfromutf8toiso88591() {
        printf "%s" "$*" | iconv -f UTF-8 -t ISO8859-1
 }
index a343bf6c629f8e6acaf7559d3168a97fcce9d286..fa686b887d6b49ab8e6d30893501744645f72a91 100755 (executable)
@@ -280,6 +280,16 @@ test_expect_success 'log --graph with merge' '
        test_cmp expect actual
 '
 
+test_expect_success 'log --raw --graph -m with merge' '
+       git log --raw --graph --oneline -m master | head -n 500 >actual &&
+       grep "initial" actual
+'
+
+test_expect_success 'diff-tree --graph' '
+       git diff-tree --graph master^ | head -n 500 >actual &&
+       grep "one" actual
+'
+
 cat > expect <<\EOF
 *   commit master
 |\  Merge: A B
index 46c3fe76d3867be394c6b9089a4aa9a1f3f6bba0..d0b2a457b8bf30fc7ab472ff6b2576ff319432f7 100755 (executable)
@@ -254,4 +254,48 @@ EXPECTED
        test_cmp expected actual
 '
 
+test_expect_success 'turn file to tree' '
+       git reset --hard initial &&
+       rm initial-file &&
+       mkdir initial-file &&
+       test_commit "turn-file-to-tree" "initial-file/ONE" "CCC" &&
+       git merge-tree initial initial turn-file-to-tree >actual &&
+       cat >expect <<-\EOF &&
+       added in remote
+         their  100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 initial-file/ONE
+       @@ -0,0 +1 @@
+       +CCC
+       removed in remote
+         base   100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file
+         our    100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file
+       @@ -1 +0,0 @@
+       -initial
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'turn tree to file' '
+       git reset --hard initial &&
+       mkdir dir &&
+       test_commit "add-tree" "dir/path" "AAA" &&
+       test_commit "add-another-tree" "dir/another" "BBB" &&
+       rm -fr dir &&
+       test_commit "make-file" "dir" "CCC" &&
+       git merge-tree add-tree add-another-tree make-file >actual &&
+       cat >expect <<-\EOF &&
+       added in local
+         our    100644 ba629238ca89489f2b350e196ca445e09d8bb834 dir/another
+       removed in remote
+         base   100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
+         our    100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
+       @@ -1 +0,0 @@
+       -AAA
+       added in remote
+         their  100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 dir
+       @@ -0,0 +1 @@
+       +CCC
+       EOF
+       test_cmp expect actual
+'
+
 test_done
index ecf00edab2079099e201237c1936cf715148a684..e7c240fc1f8333c933f22bc1af6bf57eb9ae27cb 100755 (executable)
@@ -25,32 +25,11 @@ commit id embedding:
 '
 
 . ./test-lib.sh
-UNZIP=${UNZIP:-unzip}
 GZIP=${GZIP:-gzip}
 GUNZIP=${GUNZIP:-gzip -d}
 
 SUBSTFORMAT=%H%n
 
-check_zip() {
-       zipfile=$1.zip
-       listfile=$1.lst
-       dir=$1
-       dir_with_prefix=$dir/$2
-
-       test_expect_success UNZIP " extract ZIP archive" "
-               (mkdir $dir && cd $dir && $UNZIP ../$zipfile)
-       "
-
-       test_expect_success UNZIP " validate filenames" "
-               (cd ${dir_with_prefix}a && find .) | sort >$listfile &&
-               test_cmp a.lst $listfile
-       "
-
-       test_expect_success UNZIP " validate file contents" "
-               diff -r a ${dir_with_prefix}a
-       "
-}
-
 test_expect_success \
     'populate workdir' \
     'mkdir a b c &&
@@ -201,61 +180,11 @@ test_expect_success \
       test_cmp a/substfile2 g/prefix/a/substfile2
 '
 
-$UNZIP -v >/dev/null 2>&1
-if [ $? -eq 127 ]; then
-       say "Skipping ZIP tests, because unzip was not found"
-else
-       test_set_prereq UNZIP
-fi
-
-test_expect_success \
-    'git archive --format=zip' \
-    'git archive --format=zip HEAD >d.zip'
-
-check_zip d
-
-test_expect_success \
-    'git archive --format=zip in a bare repo' \
-    '(cd bare.git && git archive --format=zip HEAD) >d1.zip'
-
-test_expect_success \
-    'git archive --format=zip vs. the same in a bare repo' \
-    'test_cmp d.zip d1.zip'
-
-test_expect_success 'git archive --format=zip with --output' \
-    'git archive --format=zip --output=d2.zip HEAD &&
-    test_cmp d.zip d2.zip'
-
-test_expect_success 'git archive with --output, inferring format' '
-       git archive --output=d3.zip HEAD &&
-       test_cmp d.zip d3.zip
-'
-
 test_expect_success 'git archive with --output, override inferred format' '
        git archive --format=tar --output=d4.zip HEAD &&
        test_cmp b.tar d4.zip
 '
 
-test_expect_success \
-    'git archive --format=zip with prefix' \
-    'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
-
-check_zip e prefix/
-
-test_expect_success 'git archive -0 --format=zip on large files' '
-       test_config core.bigfilethreshold 1 &&
-       git archive -0 --format=zip HEAD >large.zip
-'
-
-check_zip large
-
-test_expect_success 'git archive --format=zip on large files' '
-       test_config core.bigfilethreshold 1 &&
-       git archive --format=zip HEAD >large-compressed.zip
-'
-
-check_zip large-compressed
-
 test_expect_success \
     'git archive --list outside of a git repo' \
     'GIT_DIR=some/non-existing/directory git archive --list'
diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh
new file mode 100755 (executable)
index 0000000..0c847fb
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='git archive attribute pattern tests'
+
+. ./test-lib.sh
+
+test_expect_exists() {
+       test_expect_success " $1 exists" "test -e $1"
+}
+
+test_expect_missing() {
+       test_expect_success " $1 does not exist" "test ! -e $1"
+}
+
+test_expect_success 'setup' '
+       echo ignored >ignored &&
+       echo ignored export-ignore >>.git/info/attributes &&
+       git add ignored &&
+
+       mkdir not-ignored-dir &&
+       echo ignored-in-tree >not-ignored-dir/ignored &&
+       echo not-ignored-in-tree >not-ignored-dir/ignored-only-if-dir &&
+       git add not-ignored-dir &&
+
+       mkdir ignored-only-if-dir &&
+       echo ignored by ignored dir >ignored-only-if-dir/ignored-by-ignored-dir &&
+       echo ignored-only-if-dir/ export-ignore >>.git/info/attributes &&
+       git add ignored-only-if-dir &&
+
+
+       mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir &&
+       echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir &&
+       git add one-level-lower &&
+
+       git commit -m. &&
+
+       git clone --bare . bare &&
+       cp .git/info/attributes bare/info/attributes
+'
+
+test_expect_success 'git archive' '
+       git archive HEAD >archive.tar &&
+       (mkdir archive && cd archive && "$TAR" xf -) <archive.tar
+'
+
+test_expect_missing    archive/ignored
+test_expect_missing    archive/not-ignored-dir/ignored
+test_expect_exists     archive/not-ignored-dir/ignored-only-if-dir
+test_expect_exists     archive/not-ignored-dir/
+test_expect_missing    archive/ignored-only-if-dir/
+test_expect_missing    archive/ignored-ony-if-dir/ignored-by-ignored-dir
+test_expect_exists     archive/one-level-lower/
+test_expect_missing    archive/one-level-lower/two-levels-lower/ignored-only-if-dir/
+test_expect_missing    archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir
+
+
+test_done
diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh
new file mode 100755 (executable)
index 0000000..7cfe9ca
--- /dev/null
@@ -0,0 +1,131 @@
+#!/bin/sh
+
+test_description='git archive --format=zip test'
+
+. ./test-lib.sh
+GIT_UNZIP=${GIT_UNZIP:-unzip}
+
+SUBSTFORMAT=%H%n
+
+test_lazy_prereq UNZIP '
+       "$GIT_UNZIP" -v
+       test $? -ne 127
+'
+
+test_lazy_prereq UNZIP_SYMLINKS '
+       (
+               mkdir unzip-symlinks &&
+               cd unzip-symlinks &&
+               "$GIT_UNZIP" "$TEST_DIRECTORY"/t5003/infozip-symlinks.zip &&
+               test -h symlink
+       )
+'
+
+check_zip() {
+       zipfile=$1.zip
+       listfile=$1.lst
+       dir=$1
+       dir_with_prefix=$dir/$2
+
+       test_expect_success UNZIP " extract ZIP archive" '
+               (mkdir $dir && cd $dir && "$GIT_UNZIP" ../$zipfile)
+       '
+
+       test_expect_success UNZIP " validate filenames" "
+               (cd ${dir_with_prefix}a && find .) | sort >$listfile &&
+               test_cmp a.lst $listfile
+       "
+
+       test_expect_success UNZIP " validate file contents" "
+               diff -r a ${dir_with_prefix}a
+       "
+}
+
+test_expect_success \
+    'populate workdir' \
+    'mkdir a b c &&
+     echo simple textfile >a/a &&
+     mkdir a/bin &&
+     cp /bin/sh a/bin &&
+     printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
+     printf "A not substituted O" >a/substfile2 &&
+     (p=long_path_to_a_file && cd a &&
+      for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
+      echo text >file_with_long_path)
+'
+
+test_expect_success SYMLINKS,UNZIP_SYMLINKS 'add symlink' '
+       ln -s a a/symlink_to_a
+'
+
+test_expect_success 'prepare file list' '
+       (cd a && find .) | sort >a.lst
+'
+
+test_expect_success \
+    'add ignored file' \
+    'echo ignore me >a/ignored &&
+     echo ignored export-ignore >.git/info/attributes'
+
+test_expect_success \
+    'add files to repository' \
+    'find a -type f | xargs git update-index --add &&
+     find a -type l | xargs git update-index --add &&
+     treeid=`git write-tree` &&
+     echo $treeid >treeid &&
+     git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
+     git commit-tree $treeid </dev/null)'
+
+test_expect_success \
+    'create bare clone' \
+    'git clone --bare . bare.git &&
+     cp .git/info/attributes bare.git/info/attributes'
+
+test_expect_success \
+    'remove ignored file' \
+    'rm a/ignored'
+
+test_expect_success \
+    'git archive --format=zip' \
+    'git archive --format=zip HEAD >d.zip'
+
+check_zip d
+
+test_expect_success \
+    'git archive --format=zip in a bare repo' \
+    '(cd bare.git && git archive --format=zip HEAD) >d1.zip'
+
+test_expect_success \
+    'git archive --format=zip vs. the same in a bare repo' \
+    'test_cmp d.zip d1.zip'
+
+test_expect_success 'git archive --format=zip with --output' \
+    'git archive --format=zip --output=d2.zip HEAD &&
+    test_cmp d.zip d2.zip'
+
+test_expect_success 'git archive with --output, inferring format' '
+       git archive --output=d3.zip HEAD &&
+       test_cmp d.zip d3.zip
+'
+
+test_expect_success \
+    'git archive --format=zip with prefix' \
+    'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
+
+check_zip e prefix/
+
+test_expect_success 'git archive -0 --format=zip on large files' '
+       test_config core.bigfilethreshold 1 &&
+       git archive -0 --format=zip HEAD >large.zip
+'
+
+check_zip large
+
+test_expect_success 'git archive --format=zip on large files' '
+       test_config core.bigfilethreshold 1 &&
+       git archive --format=zip HEAD >large-compressed.zip
+'
+
+check_zip large-compressed
+
+test_done
diff --git a/t/t5003/infozip-symlinks.zip b/t/t5003/infozip-symlinks.zip
new file mode 100644 (file)
index 0000000..065728c
Binary files /dev/null and b/t/t5003/infozip-symlinks.zip differ
diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh
new file mode 100755 (executable)
index 0000000..8ed58d2
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='avoiding conflicting update thru symref aliasing'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit one &&
+       git clone . src &&
+       git clone src dst1 &&
+       git clone src dst2 &&
+       test_commit two &&
+       ( cd src && git pull )
+'
+
+test_expect_success 'push' '
+       (
+               cd src &&
+               git push ../dst1 "refs/remotes/*:refs/remotes/*"
+       ) &&
+       git ls-remote src "refs/remotes/*" >expect &&
+       git ls-remote dst1 "refs/remotes/*" >actual &&
+       test_cmp expect actual &&
+       ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect &&
+       ( cd dst1 && git symbolic-ref refs/remotes/origin/HEAD ) >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'fetch' '
+       (
+               cd dst2 &&
+               git fetch ../src "refs/remotes/*:refs/remotes/*"
+       ) &&
+       git ls-remote src "refs/remotes/*" >expect &&
+       git ls-remote dst2 "refs/remotes/*" >actual &&
+       test_cmp expect actual &&
+       ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect &&
+       ( cd dst2 && git symbolic-ref refs/remotes/origin/HEAD ) >actual &&
+       test_cmp expect actual
+'
+
+test_done
index c5cd2e348c6fe47af7d94ef6852757c301f8097a..47eb76921ddd53acb63573f9af75e41ab5067f5c 100755 (executable)
@@ -157,6 +157,11 @@ test_expect_success 'GIT_SMART_HTTP can disable smart http' '
         test_must_fail git fetch)
 '
 
+test_expect_success 'invalid Content-Type rejected' '
+       test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual
+       grep "not valid:" actual
+'
+
 test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
 
 test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
index ee06d2864949de71b000402fda4378c9b483fe72..4435693bb2ca48d053003c87fccd8f8612d8b4a9 100755 (executable)
@@ -37,6 +37,16 @@ test_expect_success \
 
 test_expect_success \
     'successful clone must leave the directory' \
-    'cd bar'
+    'test -d bar'
+
+test_expect_success 'failed clone --separate-git-dir should not leave any directories' '
+       mkdir foo/.git/objects.bak/ &&
+       mv foo/.git/objects/* foo/.git/objects.bak/ &&
+       test_must_fail git clone --separate-git-dir gitdir foo worktree &&
+       test_must_fail test -e gitdir &&
+       test_must_fail test -e worktree &&
+       mv foo/.git/objects.bak/* foo/.git/objects/ &&
+       rmdir foo/.git/objects.bak
+'
 
 test_done
index 72e28ee5350926f3c4f27e2c99f8323a3eb8e57c..3e0e15fb3e0b92ab7e95789d27db34d9a1fa423c 100755 (executable)
@@ -676,9 +676,7 @@ test_expect_success 'bisect fails if tree is broken on trial commit' '
 check_same()
 {
        echo "Checking $1 is the same as $2" &&
-       git rev-parse "$1" > expected.same &&
-       git rev-parse "$2" > expected.actual &&
-       test_cmp expected.same expected.actual
+       test_cmp_rev "$1" "$2"
 }
 
 test_expect_success 'bisect: --no-checkout - start commit bad' '
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
new file mode 100755 (executable)
index 0000000..0da1214
--- /dev/null
@@ -0,0 +1,146 @@
+#!/bin/sh
+
+test_description='git-status ignored files'
+
+. ./test-lib.sh
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+?? untracked/
+EOF
+
+test_expect_success 'status untracked directory with --ignored' '
+       echo "ignored" >.gitignore &&
+       mkdir untracked &&
+       : >untracked/ignored &&
+       : >untracked/uncommitted &&
+       git status --porcelain --ignored >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+?? untracked/uncommitted
+!! untracked/ignored
+EOF
+
+test_expect_success 'status untracked directory with --ignored -u' '
+       git status --porcelain --ignored -u >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! ignored/
+EOF
+
+test_expect_success 'status ignored directory with --ignore' '
+       rm -rf untracked &&
+       mkdir ignored &&
+       : >ignored/uncommitted &&
+       git status --porcelain --ignored >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! ignored/uncommitted
+EOF
+
+test_expect_success 'status ignored directory with --ignore -u' '
+       git status --porcelain --ignored -u >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! untracked-ignored/
+EOF
+
+test_expect_success 'status untracked directory with ignored files with --ignore' '
+       rm -rf ignored &&
+       mkdir untracked-ignored &&
+       mkdir untracked-ignored/test &&
+       : >untracked-ignored/ignored &&
+       : >untracked-ignored/test/ignored &&
+       git status --porcelain --ignored >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! untracked-ignored/ignored
+!! untracked-ignored/test/ignored
+EOF
+
+test_expect_success 'status untracked directory with ignored files with --ignore -u' '
+       git status --porcelain --ignored -u >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+EOF
+
+test_expect_success 'status ignored tracked directory with --ignore' '
+       rm -rf untracked-ignored &&
+       mkdir tracked &&
+       : >tracked/committed &&
+       git add tracked/committed &&
+       git commit -m. &&
+       echo "tracked" >.gitignore &&
+       git status --porcelain --ignored >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+EOF
+
+test_expect_success 'status ignored tracked directory with --ignore -u' '
+       git status --porcelain --ignored -u >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/
+EOF
+
+test_expect_success 'status ignored tracked directory and uncommitted file with --ignore' '
+       : >tracked/uncommitted &&
+       git status --porcelain --ignored >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+?? .gitignore
+?? actual
+?? expected
+!! tracked/uncommitted
+EOF
+
+test_expect_success 'status ignored tracked directory and uncommitted file with --ignore -u' '
+       git status --porcelain --ignored -u >actual &&
+       test_cmp expected actual
+'
+
+test_done
index f919c8d34de41b2ec3fe08c217dd2c6276cf8472..8e32f190077474274dc5046df5a64f837ee696f3 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2008 Johannes Schindelin
 #
 
-test_description='Test rebasing and stashing with dirty submodules'
+test_description='Test rebasing, stashing, etc. with submodules'
 
 . ./test-lib.sh
 
@@ -20,7 +20,8 @@ test_expect_success setup '
        echo second line >> file &&
        (cd submodule && git pull) &&
        test_tick &&
-       git commit -m file-and-submodule -a
+       git commit -m file-and-submodule -a &&
+       git branch added-submodule
 
 '
 
@@ -89,4 +90,29 @@ test_expect_success 'stash with a dirty submodule' '
 
 '
 
+test_expect_success 'rebasing submodule that should conflict' '
+       git reset --hard &&
+       git checkout added-submodule &&
+       git add submodule &&
+       test_tick &&
+       git commit -m third &&
+       (
+               cd submodule &&
+               git commit --allow-empty -m extra
+       ) &&
+       git add submodule &&
+       test_tick &&
+       git commit -m fourth &&
+
+       test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 &&
+       git ls-files -s submodule >actual &&
+       (
+               cd submodule &&
+               echo "160000 $(git rev-parse HEAD^) 1   submodule" &&
+               echo "160000 $(git rev-parse HEAD^^) 2  submodule" &&
+               echo "160000 $(git rev-parse HEAD) 3    submodule"
+       ) >expect &&
+       test_cmp expect actual
+'
+
 test_done
index 5b4b694f1801f5c2284346f882cb496df9e7d74e..357375151d79d03d11275875dd10ceea42a3ba47 100755 (executable)
@@ -167,5 +167,19 @@ test_expect_success 'with failing hook (--no-verify)' '
 
 '
 
+test_expect_success 'with failing hook (merge)' '
+
+       git checkout -B other HEAD@{1} &&
+       echo "more" >> file &&
+       git add file &&
+       rm -f "$HOOK" &&
+       git commit -m other &&
+       write_script "$HOOK" <<-EOF
+       exit 1
+       EOF
+       git checkout - &&
+       test_must_fail git merge other
+
+'
 
 test_done
index b3f6eb9c684c406dd896a144caa6afc160b03226..95d651080f05930d0311ff69d3641bad403eecb2 100755 (executable)
@@ -5,7 +5,7 @@
 #                   Grenoble INP Ensimag
 #
 
-test_description='git status advices'
+test_description='git status advice'
 
 . ./test-lib.sh
 
index 4f2dfe0e3d00010679c77e66c81b3ab4509e2522..2d2f016f6f8b151f10b08e4419dc6d3bdef3d0a8 100755 (executable)
@@ -12,9 +12,13 @@ then
        test_done
 fi
 
-# We override svnrdump by placing a symlink to the svnrdump-emulator in .
-export PATH="$HOME:$PATH"
-ln -sf $GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py "$HOME/svnrdump"
+# Override svnrdump with our simulator
+PATH="$HOME:$PATH"
+export PATH PYTHON_PATH GIT_BUILD_DIR
+
+write_script "$HOME/svnrdump" <<\EOF
+exec "$PYTHON_PATH" "$GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py" "$@"
+EOF
 
 init_git () {
        rm -fr .git &&
@@ -32,8 +36,8 @@ fi
 
 test_debug '
        git --version
-       which git
-       which svnrdump
+       type git
+       type svnrdump
 '
 
 test_expect_success REMOTE_SVN 'simple fetch' '
index 69934b2e775c8591ca209c9275abc40b921ecab6..3fb3368903686c8588c51e881beaee1f29808575 100755 (executable)
@@ -25,8 +25,9 @@ GIT_DIR=$PWD/.git
 export CVSROOT CVSWORK GIT_DIR
 
 rm -rf "$CVSROOT" "$CVSWORK"
-mkdir "$CVSROOT" &&
+
 cvs init &&
+test -d "$CVSROOT" &&
 cvs -Q co -d "$CVSWORK" . &&
 echo >empty &&
 git add empty &&
index 3a8e7d3f5aa1dc6a4d13467babd96a293ee1bb6e..86dfee2e4f93750aa72c0b24df57c77faa091aa7 100755 (executable)
@@ -40,7 +40,7 @@ check_snapshot () {
        echo "basename=$basename"
        grep "filename=.*$basename.tar" gitweb.headers >/dev/null 2>&1 &&
        "$TAR" tf gitweb.body >file_list &&
-       ! grep -v "^$prefix/" file_list
+       ! grep -v -e "^$prefix$" -e "^$prefix/" -e "^pax_global_header$" file_list
 }
 
 test_expect_success setup '
index 21924dfd7db4fd5b8c0eb2c2823580ae33e73cc1..aae1a3f816eb0f57f84053d74246a8db7d7529d8 100755 (executable)
@@ -105,12 +105,13 @@ build_gendouble() {
        cat >gendouble.py <<-\EOF
        import sys
        import struct
-       import array
 
-       s = array.array("c", '\0' * 26)
-       struct.pack_into(">L", s,  0, 0x00051607)  # AppleDouble
-       struct.pack_into(">L", s,  4, 0x00020000)  # version 2
-       s.tofile(sys.stdout)
+       s = struct.pack(">LL18s",
+                       0x00051607,  # AppleDouble
+                       0x00020000,  # version 2
+                       ""           # pad to 26 bytes
+       )
+       sys.stdout.write(s)
        EOF
 }
 
index 0c2fc3ea1a28268e216a3a93ed12b09f0cf55ef2..34fbc900055d9bbaa9e533063b7c69e384e07e5a 100755 (executable)
@@ -26,10 +26,8 @@ test_expect_success 'init depot' '
                line7
                line8
                EOF
-               cp filek fileko &&
-               sed -i "s/Revision/Revision: do not scrub me/" fileko
-               cp fileko file_text &&
-               sed -i "s/Id/Id: do not scrub me/" file_text
+               sed "s/Revision/Revision: do not scrub me/" <filek >fileko &&
+               sed "s/Id/Id: do not scrub me/" <fileko >file_text &&
                p4 add -t text+k filek &&
                p4 submit -d "filek" &&
                p4 add -t text+ko fileko &&
@@ -88,7 +86,8 @@ test_expect_success 'edit far away from RCS lines' '
        (
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
-               sed -i "s/^line7/line7 edit/" filek &&
+               sed "s/^line7/line7 edit/" <filek >filek.tmp &&
+               mv -f filek.tmp filek &&
                git commit -m "filek line7 edit" filek &&
                git p4 submit &&
                scrub_k_check filek
@@ -105,7 +104,8 @@ test_expect_success 'edit near RCS lines' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "s/^line4/line4 edit/" filek &&
+               sed "s/^line4/line4 edit/" <filek >filek.tmp &&
+               mv -f filek.tmp filek &&
                git commit -m "filek line4 edit" filek &&
                git p4 submit &&
                scrub_k_check filek
@@ -122,7 +122,8 @@ test_expect_success 'edit keyword lines' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "/Revision/d" filek &&
+               sed "/Revision/d" <filek >filek.tmp &&
+               mv -f filek.tmp filek &&
                git commit -m "filek remove Revision line" filek &&
                git p4 submit &&
                scrub_k_check filek
@@ -139,7 +140,8 @@ test_expect_success 'scrub ko files differently' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "s/^line4/line4 edit/" fileko &&
+               sed "s/^line4/line4 edit/" <fileko >fileko.tmp &&
+               mv -f fileko.tmp fileko &&
                git commit -m "fileko line4 edit" fileko &&
                git p4 submit &&
                scrub_ko_check fileko &&
@@ -189,12 +191,14 @@ test_expect_success 'do not scrub plain text' '
                cd "$git" &&
                git config git-p4.skipSubmitEdit true &&
                git config git-p4.attemptRCSCleanup true &&
-               sed -i "s/^line4/line4 edit/" file_text &&
+               sed "s/^line4/line4 edit/" <file_text >file_text.tmp &&
+               mv -f file_text.tmp file_text &&
                git commit -m "file_text line4 edit" file_text &&
                (
                        cd "$cli" &&
                        p4 open file_text &&
-                       sed -i "s/^line5/line5 p4 edit/" file_text &&
+                       sed "s/^line5/line5 p4 edit/" <file_text >file_text.tmp &&
+                       mv -f file_text.tmp file_text &&
                        p4 submit -d "file5 p4 edit"
                ) &&
                echo s | test_expect_code 1 git p4 submit &&
index 3cd53f87fb70443bc51bfec13d92a82d7f73ec7c..adc1372b3c334b4305761f6c3922493c85a0822a 100755 (executable)
@@ -13,6 +13,25 @@ complete ()
        return 0
 }
 
+# Be careful when updating this list:
+#
+# (1) The build tree may have build artifact from different branch, or
+#     the user's $PATH may have a random executable that may begin
+#     with "git-check" that are not part of the subcommands this build
+#     will ship, e.g.  "check-ignore".  The tests for completion for
+#     subcommand names tests how "check" is expanded; we limit the
+#     possible candidates to "checkout" and "check-attr" to make sure
+#     "check-attr", which is known by the filter function as a
+#     subcommand to be thrown out, while excluding other random files
+#     that happen to begin with "check" to avoid letting them get in
+#     the way.
+#
+# (2) A test makes sure that common subcommands are included in the
+#     completion for "git <TAB>", and a plumbing is excluded.  "add",
+#     "filter-branch" and "ls-files" are listed for this.
+
+GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'
+
 . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash"
 
 # We don't need this function to actually join words or do anything special.
@@ -196,7 +215,6 @@ test_expect_success 'general options plus command' '
        test_completion "git --paginate check" "checkout " &&
        test_completion "git --git-dir=foo check" "checkout " &&
        test_completion "git --bare check" "checkout " &&
-       test_completion "git --help des" "describe " &&
        test_completion "git --exec-path=foo check" "checkout " &&
        test_completion "git --html-path check" "checkout " &&
        test_completion "git --no-pager check" "checkout " &&
@@ -207,6 +225,11 @@ test_expect_success 'general options plus command' '
        test_completion "git --no-replace-objects check" "checkout "
 '
 
+test_expect_success 'git --help completion' '
+       test_completion "git --help ad" "add " &&
+       test_completion "git --help core" "core-tutorial "
+'
+
 test_expect_success 'setup for ref completion' '
        echo content >file1 &&
        echo more >file2 &&
index 22a4f8fb64a4e8084139fc148e8e7dd4aa73d684..fa62d010f68e3ee97e6754687ad4d08564d3c96b 100644 (file)
@@ -602,6 +602,13 @@ test_cmp() {
        $GIT_TEST_CMP "$@"
 }
 
+# Tests that its two parameters refer to the same revision
+test_cmp_rev () {
+       git rev-parse --verify "$1" >expect.rev &&
+       git rev-parse --verify "$2" >actual.rev &&
+       test_cmp expect.rev actual.rev
+}
+
 # Print a sequence of numbers or letters in increasing order.  This is
 # similar to GNU seq(1), but the latter might not be available
 # everywhere (and does not do letters).  It may be used like:
index f50f8341d40c6ec87565d01a263d97209fb68680..ea1e4a03a7b61392c0a068cb55006165e9a7394a 100644 (file)
@@ -85,7 +85,8 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
                .*_TEST
                PROVE
                VALGRIND
-               PERF_AGGREGATING_LATER
+               UNZIP
+               PERF_
        ));
        my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
        print join("\n", @vars);
@@ -128,6 +129,7 @@ fi
 unset CDPATH
 
 unset GREP_OPTIONS
+unset UNZIP
 
 case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
 1|2|true)
index 10172aee18292b50aa24b3a8694b5383c1cfd98e..1fb373f25bac42648a0779ffd42f1ae0eaec359a 100755 (executable)
@@ -31,7 +31,7 @@ sub finish_child {
        } elsif ($? & 127) {
                my $code = $? & 127;
                warn "died of signal $code";
-               return $code - 128;
+               return $code + 128;
        } else {
                return $? >> 8;
        }
index 3bc20e91da561f4edd5c3eddb0988735759234e4..0092cbf3540e2fdfd2e882461ba39ba2a833b672 100644 (file)
@@ -1,4 +1,32 @@
 #include "cache.h"
+#include "string-list.h"
+
+/*
+ * A "string_list_each_func_t" function that normalizes an entry from
+ * GIT_CEILING_DIRECTORIES.  If the path is unusable for some reason,
+ * die with an explanation.
+ */
+static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
+{
+       const char *ceil = item->string;
+       int len = strlen(ceil);
+       char buf[PATH_MAX+1];
+
+       if (len == 0)
+               die("Empty path is not supported");
+       if (len > PATH_MAX)
+               die("Path \"%s\" is too long", ceil);
+       if (!is_absolute_path(ceil))
+               die("Path \"%s\" is not absolute", ceil);
+       if (normalize_path_copy(buf, ceil) < 0)
+               die("Path \"%s\" could not be normalized", ceil);
+       len = strlen(buf);
+       if (len > 1 && buf[len-1] == '/')
+               die("Normalized path \"%s\" ended with slash", buf);
+       free(item->string);
+       item->string = xstrdup(buf);
+       return 1;
+}
 
 int main(int argc, char **argv)
 {
@@ -30,7 +58,28 @@ int main(int argc, char **argv)
        }
 
        if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
-               int len = longest_ancestor_length(argv[2], argv[3]);
+               int len;
+               struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
+               char *path = xstrdup(argv[2]);
+
+               /*
+                * We have to normalize the arguments because under
+                * Windows, bash mangles arguments that look like
+                * absolute POSIX paths or colon-separate lists of
+                * absolute POSIX paths into DOS paths (e.g.,
+                * "/foo:/foo/bar" might be converted to
+                * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"),
+                * whereas longest_ancestor_length() requires paths
+                * that use forward slashes.
+                */
+               if (normalize_path_copy(path, path))
+                       die("Path \"%s\" could not be normalized", argv[2]);
+               string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1);
+               filter_string_list(&ceiling_dirs, 0,
+                                  normalize_ceiling_entry, NULL);
+               len = longest_ancestor_length(path, &ceiling_dirs);
+               string_list_clear(&ceiling_dirs, 0);
+               free(path);
                printf("%d\n", len);
                return 0;
        }
index 4693295a98ca713fa65eb9b67d50113ec97ecf71..00ce6c9a129674c1922e0c388366592c5ae7c8c7 100644 (file)
@@ -97,26 +97,6 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       if (argc == 4 && !strcmp(argv[1], "longest_prefix")) {
-               /* arguments: <colon-separated-prefixes>|- <string> */
-               struct string_list prefixes = STRING_LIST_INIT_DUP;
-               int retval;
-               const char *prefix_string = argv[2];
-               const char *string = argv[3];
-               const char *match;
-
-               parse_string_list(&prefixes, prefix_string);
-               match = string_list_longest_prefix(&prefixes, string);
-               if (match) {
-                       printf("%s\n", match);
-                       retval = 0;
-               }
-               else
-                       retval = 1;
-               string_list_clear(&prefixes, 0);
-               return retval;
-       }
-
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
index 9932f402dfee2605dbb498b120813aebaa3961f8..b9306ef64543d4eb705354ac170d9acc7b735ec5 100644 (file)
@@ -741,7 +741,7 @@ void transport_print_push_status(const char *dest, struct ref *refs,
                        n += print_one_push_status(ref, dest, n, porcelain);
                if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD &&
                    *nonfastforward != NON_FF_HEAD) {
-                       if (!strcmp(head, ref->name))
+                       if (head != NULL && !strcmp(head, ref->name))
                                *nonfastforward = NON_FF_HEAD;
                        else
                                *nonfastforward = NON_FF_OTHER;
diff --git a/utf8.c b/utf8.c
index 5c61bbe1131e7bbdd939c8b815bd5222b872e3fb..1087870c51caff3dd86a852ec5e8bf5875f6d797 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -323,7 +323,7 @@ static size_t display_mode_esc_sequence_len(const char *s)
  * If indent is negative, assume that already -indent columns have been
  * consumed (and no extra indent is necessary for the first line).
  */
-int strbuf_add_wrapped_text(struct strbuf *buf,
+void strbuf_add_wrapped_text(struct strbuf *buf,
                const char *text, int indent1, int indent2, int width)
 {
        int indent, w, assume_utf8 = 1;
@@ -332,7 +332,7 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
 
        if (width <= 0) {
                strbuf_add_indented_text(buf, text, indent1, indent2);
-               return 1;
+               return;
        }
 
 retry:
@@ -356,14 +356,14 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
                        if (w <= width || !space) {
                                const char *start = bol;
                                if (!c && text == start)
-                                       return w;
+                                       return;
                                if (space)
                                        start = space;
                                else
                                        strbuf_addchars(buf, ' ', indent);
                                strbuf_add(buf, start, text - start);
                                if (!c)
-                                       return w;
+                                       return;
                                space = text;
                                if (c == '\t')
                                        w |= 0x07;
@@ -405,13 +405,12 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
        }
 }
 
-int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
                             int indent, int indent2, int width)
 {
        char *tmp = xstrndup(data, len);
-       int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
+       strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
        free(tmp);
-       return r;
 }
 
 int is_encoding_utf8(const char *name)
@@ -430,6 +429,27 @@ int same_encoding(const char *src, const char *dst)
        return !strcasecmp(src, dst);
 }
 
+/*
+ * Wrapper for fprintf and returns the total number of columns required
+ * for the printed string, assuming that the string is utf8.
+ */
+int utf8_fprintf(FILE *stream, const char *format, ...)
+{
+       struct strbuf buf = STRBUF_INIT;
+       va_list arg;
+       int columns;
+
+       va_start(arg, format);
+       strbuf_vaddf(&buf, format, arg);
+       va_end(arg);
+
+       columns = fputs(buf.buf, stream);
+       if (0 <= columns) /* keep the error from the I/O */
+               columns = utf8_strwidth(buf.buf);
+       strbuf_release(&buf);
+       return columns;
+}
+
 /*
  * Given a buffer and its encoding, return it re-encoded
  * with iconv.  If the conversion fails, returns NULL.
diff --git a/utf8.h b/utf8.h
index 93ef60042c2fad93184b573f30e771ecddc842be..501b2bd9c4fd3fdce6dcbba1a3e3f7c0211d6c8f 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -8,10 +8,11 @@ int utf8_strwidth(const char *string);
 int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
 int same_encoding(const char *, const char *);
+int utf8_fprintf(FILE *, const char *, ...);
 
-int strbuf_add_wrapped_text(struct strbuf *buf,
+void strbuf_add_wrapped_text(struct strbuf *buf,
                const char *text, int indent, int indent2, int width);
-int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
                             int indent, int indent2, int width);
 
 #ifndef NO_ICONV
index 68739aaa3b9e9e1a1bbbd43c75c9b5c244fb6c3e..bac59d2c41bae7441038b30728c696b6280f4c2d 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -229,7 +229,7 @@ int xmkstemp(char *template)
                int saved_errno = errno;
                const char *nonrelative_template;
 
-               if (!template[0])
+               if (strlen(template) != strlen(origtemplate))
                        template = origtemplate;
 
                nonrelative_template = absolute_path(template);
@@ -411,11 +411,19 @@ void warn_on_inaccessible(const char *path)
 int access_or_warn(const char *path, int mode)
 {
        int ret = access(path, mode);
-       if (ret && errno != ENOENT)
+       if (ret && errno != ENOENT && errno != ENOTDIR)
                warn_on_inaccessible(path);
        return ret;
 }
 
+int access_or_die(const char *path, int mode)
+{
+       int ret = access(path, mode);
+       if (ret && errno != ENOENT && errno != ENOTDIR)
+               die_errno(_("unable to access '%s'"), path);
+       return ret;
+}
+
 struct passwd *xgetpwuid_self(void)
 {
        struct passwd *pw;
index 2a9658bad4c5035893e9363b51985f285dd3b34c..d7cfe8f31cd3d2b4b8bdc18c5da2449255b0531b 100644 (file)
@@ -516,7 +516,9 @@ static void wt_status_collect_untracked(struct wt_status *s)
 
        if (s->show_ignored_files) {
                dir.nr = 0;
-               dir.flags = DIR_SHOW_IGNORED | DIR_SHOW_OTHER_DIRECTORIES;
+               dir.flags = DIR_SHOW_IGNORED;
+               if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
+                       dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
                fill_directory(&dir, s->pathspec);
                for (i = 0; i < dir.nr; i++) {
                        struct dir_entry *ent = dir.entries[i];