Imported Upstream version 1.8.1.3 upstream/1.8.1.3
authorAnas Nashif <anas.nashif@intel.com>
Fri, 15 Feb 2013 19:39:29 +0000 (11:39 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Fri, 15 Feb 2013 19:39:29 +0000 (11:39 -0800)
318 files changed:
.gitignore
.mailmap
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/RelNotes/1.8.0.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.0.2.txt [new file with mode: 0644]
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.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/diff-config.txt
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/git-bisect-lk2009.txt
Documentation/git-bundle.txt
Documentation/git-checkout.txt
Documentation/git-clone.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-cvsimport.txt
Documentation/git-diff.txt
Documentation/git-fast-import.txt
Documentation/git-fetch-pack.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-merge.txt
Documentation/git-notes.txt
Documentation/git-push.txt
Documentation/git-remote-helpers.txt
Documentation/git-reset.txt
Documentation/git-rm.txt
Documentation/git-send-email.txt
Documentation/git-shortlog.txt
Documentation/git-stash.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git-symbolic-ref.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitmodules.txt
Documentation/gitrepository-layout.txt
Documentation/howto/maintain-git.txt
Documentation/howto/new-command.txt [new file with mode: 0644]
Documentation/howto/rebase-from-internal-branch.txt
Documentation/howto/rebuild-from-update-hook.txt
Documentation/howto/recover-corrupted-blob-object.txt
Documentation/howto/revert-a-faulty-merge.txt
Documentation/howto/revert-branch-rebase.txt
Documentation/howto/separating-topic-branches.txt
Documentation/howto/setup-git-server-over-http.txt
Documentation/howto/update-hook-example.txt
Documentation/howto/use-git-daemon.txt
Documentation/howto/using-signed-tag-in-pull-request.txt
Documentation/mailmap.txt
Documentation/merge-config.txt
Documentation/pt_BR/gittutorial.txt [deleted file]
Documentation/rev-list-options.txt
Documentation/technical/api-allocation-growing.txt
Documentation/technical/api-argv-array.txt
Documentation/technical/api-history-graph.txt
Documentation/technical/api-index-skel.txt
Documentation/technical/api-run-command.txt
Documentation/technical/api-strbuf.txt
Documentation/technical/api-string-list.txt
Documentation/technical/index-format.txt
Documentation/technical/pack-format.txt
Documentation/technical/pack-protocol.txt
Documentation/technical/send-pack-pipeline.txt
Documentation/technical/shallow.txt
Documentation/technical/trivial-merge.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
INSTALL
Makefile
README
RelNotes
abspath.c
archive-tar.c
archive-zip.c
archive.c
argv-array.c
argv-array.h
attr.c
bisect.c
bisect.h
builtin.h
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/diff-index.c
builtin/diff.c
builtin/fetch-pack.c
builtin/fmt-merge-msg.c
builtin/grep.c
builtin/help.c
builtin/log.c
builtin/mailinfo.c
builtin/merge-index.c
builtin/merge-tree.c
builtin/merge.c
builtin/pack-objects.c
builtin/pack-redundant.c
builtin/remote.c
builtin/replace.c
builtin/rev-list.c
builtin/rm.c
builtin/send-pack.c
builtin/shortlog.c
builtin/show-ref.c
builtin/symbolic-ref.c
builtin/update-index.c
cache-tree.c
cache-tree.h
cache.h
commit.c
commit.h
compat/cygwin.c
compat/fnmatch/fnmatch.c
compat/mingw.c
compat/mingw.h
compat/nedmalloc/nedmalloc.c
compat/terminal.c
config.c
config.mak.in
configure
configure.ac
contrib/completion/git-completion.bash
contrib/completion/git-completion.tcsh [new file with mode: 0644]
contrib/completion/git-completion.zsh [new file with mode: 0644]
contrib/completion/git-prompt.sh
contrib/emacs/git.el
contrib/mw-to-git/git-remote-mediawiki
contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh
contrib/remote-helpers/Makefile [new file with mode: 0644]
contrib/remote-helpers/git-remote-hg [new file with mode: 0755]
contrib/remote-helpers/test-hg-bidi.sh [new file with mode: 0755]
contrib/remote-helpers/test-hg-hg-git.sh [new file with mode: 0755]
contrib/remote-helpers/test-hg.sh [new file with mode: 0755]
contrib/stats/mailmap.pl
contrib/subtree/.gitignore
contrib/subtree/git-subtree.txt
contrib/svn-fe/svn-fe.c
contrib/svn-fe/svnrdump_sim.py [new file with mode: 0755]
contrib/vim/README
diff.c
diff.h
diffcore-pickaxe.c
dir.c
dir.h
editor.c
fetch-pack.c [new file with mode: 0644]
git-am.sh
git-compat-util.h
git-cvsimport.perl
git-cvsserver.perl
git-filter-branch.sh
git-p4.py
git-parse-remote.sh
git-pull.sh
git-rebase--interactive.sh
git-send-email.perl
git-sh-setup.sh
git-submodule.sh
git.c
git.spec
gitweb/gitweb.perl
gpg-interface.c
graph.c
grep.c
grep.h
help.c
http.c
http.h
ident.c
log-tree.c
mailmap.c
merge-blobs.c [moved from merge-file.c with 94% similarity]
merge-blobs.h [new file with mode: 0644]
merge-file.h [deleted file]
merge-recursive.c
merge-recursive.h
merge.c [new file with mode: 0644]
mergetools/p4merge
notes.c
notes.h
pager.c
path.c
perl/Git.pm
perl/Git/SVN/Prompt.pm
po/de.po
po/git.pot
po/sv.po
po/vi.po
pretty.c
refs.c
remote-curl.c
remote-testsvn.c [new file with mode: 0644]
remote.c
revision.c
revision.h
run-command.c
run-command.h
send-pack.c [new file with mode: 0644]
sequencer.c
setup.c
sha1_file.c
strbuf.c
strbuf.h
string-list.c
string-list.h
submodule.c
submodule.h
t/Makefile
t/lib-gettext.sh
t/lib-httpd/apache.conf
t/t0000-basic.sh
t/t0003-attributes.sh
t/t0007-git-var.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/t1300-repo-config.sh
t/t1400-update-ref.sh
t/t1401-symbolic-ref.sh
t/t1402-check-ref-format.sh
t/t1505-rev-parse-last.sh
t/t2020-checkout-detach.sh
t/t2203-add-intent.sh
t/t3001-ls-files-others-exclude.sh
t/t3200-branch.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/t4006-diff-mode.sh
t/t4014-format-patch.sh
t/t4030-diff-textconv.sh
t/t4041-diff-submodule-option.sh
t/t4049-diff-stat-count.sh
t/t4055-diff-context.sh [new file with mode: 0755]
t/t4201-shortlog.sh
t/t4202-log.sh
t/t4205-log-pretty-formats.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/t6050-replace.sh
t/t7003-filter-branch.sh
t/t7004-tag.sh
t/t7008-grep-binary.sh
t/t7061-wtstatus-ignore.sh [new file with mode: 0755]
t/t7400-submodule-basic.sh
t/t7402-submodule-rebase.sh
t/t7403-submodule-sync.sh
t/t7406-submodule-update.sh
t/t7407-submodule-foreach.sh
t/t7502-commit.sh
t/t7505-prepare-commit-msg-hook.sh
t/t9001-send-email.sh
t/t9020-remote-svn.sh [new file with mode: 0755]
t/t9200-git-cvsexportcommit.sh
t/t9400-git-cvsserver-server.sh
t/t9401-git-cvsserver-crlf.sh
t/t9502-gitweb-standalone-parse-output.sh
t/t9604-cvsimport-timestamps.sh [new file with mode: 0755]
t/t9604/cvsroot/.gitattributes [new file with mode: 0644]
t/t9604/cvsroot/CVSROOT/.gitignore [new file with mode: 0644]
t/t9604/cvsroot/module/a,v [new file with mode: 0644]
t/t9700/test.pl
t/t9800-git-p4-basic.sh
t/t9802-git-p4-filetype.sh
t/t9810-git-p4-rcs.sh
t/t9814-git-p4-rename.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
test-svn-fe.c
transport-helper.c
transport.c
transport.h
tree-walk.c
upload-pack.c
usage.c
utf8.c
utf8.h
vcs-svn/fast_export.c
vcs-svn/fast_export.h
vcs-svn/svndump.c
vcs-svn/svndump.h
version
wrapper.c
write_or_die.c
wt-status.c

index a188a82..726db73 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
 /git-remote-fd
 /git-remote-ext
 /git-remote-testgit
+/git-remote-testsvn
 /git-repack
 /git-replace
 /git-repo-config
index bcf4f87..c7e8618 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 57da6aa..69f7e9b 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 267dfe1..971977b 100644 (file)
@@ -21,11 +21,33 @@ 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
+SP_ARTICLES += howto/use-git-daemon
+SP_ARTICLES += howto/update-hook-example
+SP_ARTICLES += howto/setup-git-server-over-http
+SP_ARTICLES += howto/separating-topic-branches
+SP_ARTICLES += howto/revert-a-faulty-merge
+SP_ARTICLES += howto/recover-corrupted-blob-object
+SP_ARTICLES += howto/rebuild-from-update-hook
+SP_ARTICLES += howto/rebase-from-internal-branch
+SP_ARTICLES += howto/maintain-git
 API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
 SP_ARTICLES += $(API_DOCS)
+
+TECH_DOCS = technical/index-format
+TECH_DOCS += technical/pack-format
+TECH_DOCS += technical/pack-heuristics
+TECH_DOCS += technical/pack-protocol
+TECH_DOCS += technical/protocol-capabilities
+TECH_DOCS += technical/protocol-common
+TECH_DOCS += technical/racy-git
+TECH_DOCS += technical/send-pack-pipeline
+TECH_DOCS += technical/shallow
+TECH_DOCS += technical/trivial-merge
+SP_ARTICLES += $(TECH_DOCS)
 SP_ARTICLES += technical/api-index
 
 DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
@@ -156,8 +178,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)
@@ -231,11 +251,11 @@ clean:
        $(RM) *.texi *.texi+ *.texi++ git.info gitman.info
        $(RM) *.pdf
        $(RM) howto-index.txt howto/*.html doc.dep
-       $(RM) technical/api-*.html technical/api-index.txt
+       $(RM) technical/*.html technical/api-index.txt
        $(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 $@+ $< && \
@@ -248,7 +268,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 $@+ $< && \
@@ -264,7 +284,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): %.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
 
@@ -309,7 +329,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.1.txt b/Documentation/RelNotes/1.8.0.1.txt
new file mode 100644 (file)
index 0000000..1f372fa
--- /dev/null
@@ -0,0 +1,64 @@
+Git v1.8.0.1 Release Notes
+==========================
+
+Fixes since v1.8.0
+------------------
+
+ * The configuration parser had an unnecessary hardcoded limit on
+   variable names that was not checked consistently.
+
+ * The "say" function in the test scaffolding incorrectly allowed
+   "echo" to interpret "\a" as if it were a C-string asking for a
+   BEL output.
+
+ * "git mergetool" feeds /dev/null as a common ancestor when dealing
+   with an add/add conflict, but p4merge backend cannot handle
+   it. Work it around by passing a temporary empty file.
+
+ * "git log -F -E --grep='<ere>'" failed to use the given <ere>
+   pattern as extended regular expression, and instead looked for the
+   string literally.
+
+ * "git grep -e pattern <tree>" asked the attribute system to read
+   "<tree>:.gitattributes" file in the working tree, which was
+   nonsense.
+
+ * A symbolic ref refs/heads/SYM was not correctly removed with "git
+   branch -d SYM"; the command removed the ref pointed by SYM
+   instead.
+
+ * Earlier we fixed documentation to hyphenate "remote-tracking branch"
+   to clarify that these are not a remote entity, but unhyphenated
+   spelling snuck in to a few places since then.
+
+ * "git pull --rebase" run while the HEAD is detached tried to find
+   the upstream branch of the detached HEAD (which by definition
+   does not exist) and emitted unnecessary error messages.
+
+ * The refs/replace hierarchy was not mentioned in the
+   repository-layout docs.
+
+ * Sometimes curl_multi_timeout() function suggested a wrong timeout
+   value when there is no file descriptors to wait on and the http
+   transport ended up sleeping for minutes in select(2) system call.
+   A workaround has been added for this.
+
+ * Various rfc2047 quoting issues around a non-ASCII name on the
+   From: line in the output from format-patch have been corrected.
+
+ * "git diff -G<pattern>" did not honor textconv filter when looking
+   for changes.
+
+ * Bash completion script (in contrib/) did not correctly complete a
+   lazy "git checkout $name_of_remote_tracking_branch_that_is_unique"
+   command line.
+
+ * RSS feed from "gitweb" had a xss hole in its title output.
+
+ * "git config --path $key" segfaulted on "[section] key" (a boolean
+   "true" spelled without "=", not "[section] key = true").
+
+ * "git checkout -b foo" while on an unborn branch did not say
+   "Switched to a new branch 'foo'" like other cases.
+
+Also contains other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.8.0.2.txt b/Documentation/RelNotes/1.8.0.2.txt
new file mode 100644 (file)
index 0000000..8497e05
--- /dev/null
@@ -0,0 +1,34 @@
+Git v1.8.0.2 Release Notes
+==========================
+
+Fixes since v1.8.0.1
+--------------------
+
+ * Various codepaths have workaround for a common misconfiguration to
+   spell "UTF-8" as "utf8", but it was not used uniformly.  Most
+   notably, mailinfo (which is used by "git am") lacked this support.
+
+ * We failed to mention a file without any content change but whose
+   permission bit was modified, or (worse yet) a new file without any
+   content in the "git diff --stat" output.
+
+ * When "--stat-count" hides a diffstat for binary contents, the total
+   number of added and removed lines at the bottom was computed
+   incorrectly.
+
+ * When "--stat-count" hides a diffstat for unmerged paths, the total
+   number of affected files at the bottom of the "diff --stat" output
+   was computed incorrectly.
+
+ * "diff --shortstat" miscounted the total number of affected files
+   when there were unmerged paths.
+
+ * "git p4" used to try expanding malformed "$keyword$" that spans
+   across multiple lines.
+
+ * "git update-ref -d --deref SYM" to delete a ref through a symbolic
+   ref that points to it did not remove it correctly.
+
+ * Syntax highlighting in "gitweb" was not quite working.
+
+Also contains other minor fixes and documentation updates.
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.txt b/Documentation/RelNotes/1.8.1.txt
new file mode 100644 (file)
index 0000000..d6f9555
--- /dev/null
@@ -0,0 +1,241 @@
+Git v1.8.1 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+In the next major release (not *this* one), we will change the
+behavior of the "git push" command.
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  We will use the "simple" semantics that pushes the
+current branch to the branch with the same name, only when the current
+branch is set to integrate with that remote branch.  There is a user
+preference configuration variable "push.default" to change this, and
+"git push" will warn about the upcoming change until you set this
+variable in this release.
+
+"git branch --set-upstream" is deprecated and may be removed in a
+relatively distant future.  "git branch [-u|--set-upstream-to]" has
+been introduced with a saner order of arguments to replace it.
+
+
+Updates since v1.8.0
+--------------------
+
+UI, Workflows & Features
+
+ * Command-line completion scripts for tcsh and zsh have been added.
+
+ * "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.
+
+ * 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
+   them up by pushing or pulling.  This can be disabled with the
+   advice.statusHints configuration variable.
+
+ * "git config --get" used to diagnose presence of multiple
+   definitions of the same variable in the same configuration file as
+   an error, but it now applies the "last one wins" rule used by the
+   internal configuration logic.  Strictly speaking, this may be an
+   API regression but it is expected that nobody will notice it in
+   practice.
+
+ * 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".
+
+ * "git replace -d <object>" now interprets <object> as an extended
+   SHA-1 (e.g. HEAD~4 is allowed), instead of only accepting full hex
+   object name.
+
+ * "git rm $submodule" used to punt on removing a submodule working
+   tree to avoid losing the repository embedded in it.  Because
+   recent git uses a mechanism to separate the submodule repository
+   from the submodule working tree, "git rm" learned to detect this
+   case and removes the submodule working tree when it is safe to do so.
+
+ * "git send-email" used to prompt for the sender address, even when
+   the committer identity is well specified (e.g. via user.name and
+   user.email configuration variables).  The command no longer gives
+   this prompt when not necessary.
+
+ * "git send-email" did not allow non-address garbage strings to
+   appear after addresses on Cc: lines in the patch files (and when
+   told to pick them up to find more recipients), e.g.
+
+     Cc: Stable Kernel <stable@k.org> # for v3.2 and up
+
+   The command now strips " # for v3.2 and up" part before adding the
+   remainder of this line to the list of recipients.
+
+ * "git submodule add" learned to add a new submodule at the same
+   path as the path where an unrelated submodule was bound to in an
+   existing revision via the "--name" option.
+
+ * "git submodule sync" learned the "--recursive" option.
+
+ * "diff.submodule" configuration variable can be used to give custom
+   default value to the "git diff --submodule" option.
+
+ * "git symbolic-ref" learned the "-d $symref" option to delete the
+   named symbolic ref, which is more intuitive way to spell it than
+   "update-ref -d --no-deref $symref".
+
+
+Foreign Interface
+
+ * "git cvsimport" can be told to record timezones (other than GMT)
+   per-author via its author info file.
+
+ * 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.
+
+
+Performance, Internal Implementation, etc.
+
+ * Compilation on Cygwin with newer header files are supported now.
+
+ * A couple of low-level implementation updates on MinGW.
+
+ * The logic to generate the initial advertisement from "upload-pack"
+   (i.e. what is invoked by "git fetch" on the other side of the
+   connection) to list what refs are available in the repository has
+   been optimized.
+
+ * The logic to find set of attributes that match a given path has
+   been optimized.
+
+ * Use preloadindex in "git diff-index" and "git update-index", which
+   has a nice speedup on systems with slow stat calls (and even on
+   Linux).
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.8.0
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.0 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * The configuration parser had an unnecessary hardcoded limit on
+   variable names that was not checked consistently.
+
+ * The "say" function in the test scaffolding incorrectly allowed
+   "echo" to interpret "\a" as if it were a C-string asking for a
+   BEL output.
+
+ * "git mergetool" feeds /dev/null as a common ancestor when dealing
+   with an add/add conflict, but p4merge backend cannot handle
+   it. Work it around by passing a temporary empty file.
+
+ * "git log -F -E --grep='<ere>'" failed to use the given <ere>
+   pattern as extended regular expression, and instead looked for the
+   string literally.
+
+ * "git grep -e pattern <tree>" asked the attribute system to read
+   "<tree>:.gitattributes" file in the working tree, which was
+   nonsense.
+
+ * A symbolic ref refs/heads/SYM was not correctly removed with "git
+   branch -d SYM"; the command removed the ref pointed by SYM
+   instead.
+
+ * Update "remote tracking branch" in the documentation to
+   "remote-tracking branch".
+
+ * "git pull --rebase" run while the HEAD is detached tried to find
+   the upstream branch of the detached HEAD (which by definition
+   does not exist) and emitted unnecessary error messages.
+
+ * The refs/replace hierarchy was not mentioned in the
+   repository-layout docs.
+
+ * Various rfc2047 quoting issues around a non-ASCII name on the
+   From: line in the output from format-patch have been corrected.
+
+ * Sometimes curl_multi_timeout() function suggested a wrong timeout
+   value when there is no file descriptor to wait on and the http
+   transport ended up sleeping for minutes in select(2) system call.
+   A workaround has been added for this.
+
+ * For a fetch refspec (or the result of applying wildcard on one),
+   we always want the RHS to map to something inside "refs/"
+   hierarchy, but the logic to check it was not exactly right.
+   (merge 5c08c1f jc/maint-fetch-tighten-refname-check later to maint).
+
+ * "git diff -G<pattern>" did not honor textconv filter when looking
+   for changes.
+
+ * Some HTTP servers ask for auth only during the actual packing phase
+   (not in ls-remote phase); this is not really a recommended
+   configuration, but the clients used to fail to authenticate with
+   such servers.
+   (merge 2e736fd jk/maint-http-half-auth-fetch later to maint).
+
+ * "git p4" used to try expanding malformed "$keyword$" that spans
+   across multiple lines.
+
+ * Syntax highlighting in "gitweb" was not quite working.
+
+ * RSS feed from "gitweb" had a xss hole in its title output.
+
+ * "git config --path $key" segfaulted on "[section] key" (a boolean
+   "true" spelled without "=", not "[section] key = true").
+
+ * "git checkout -b foo" while on an unborn branch did not say
+   "Switched to a new branch 'foo'" like other cases.
+
+ * Various codepaths have workaround for a common misconfiguration to
+   spell "UTF-8" as "utf8", but it was not used uniformly.  Most
+   notably, mailinfo (which is used by "git am") lacked this support.
+
+ * We failed to mention a file without any content change but whose
+   permission bit was modified, or (worse yet) a new file without any
+   content in the "git diff --stat" output.
+
+ * When "--stat-count" hides a diffstat for binary contents, the total
+   number of added and removed lines at the bottom was computed
+   incorrectly.
+
+ * When "--stat-count" hides a diffstat for unmerged paths, the total
+   number of affected files at the bottom of the "diff --stat" output
+   was computed incorrectly.
+
+ * "diff --shortstat" miscounted the total number of affected files
+   when there were unmerged paths.
+
+ * "update-ref -d --deref SYM" to delete a ref through a symbolic ref
+   that points to it did not remove it correctly.
index 0dbf2c9..90133d8 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.
 
@@ -179,7 +155,8 @@ message starts, you can put a "From: " line to name that person.
 
 You often want to add additional explanation about the patch,
 other than the commit message itself.  Place such "cover letter"
-material between the three dash lines and the diffstat.
+material between the three dash lines and the diffstat. Git-notes
+can also be inserted using the `--notes` option.
 
 Do not attach the patch as a MIME attachment, compressed or not.
 Do not let your e-mail client send quoted-printable.  Do not let
@@ -207,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 +273,26 @@ 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
 
 Here is an ideal patch flow for this project the current maintainer
index 11f320b..e452ff8 100644 (file)
@@ -160,9 +160,10 @@ advice.*::
                it resulted in a non-fast-forward error.
        statusHints::
                Show directions on how to proceed from the current
-               state in the output of linkgit:git-status[1] and in
+               state in the output of linkgit:git-status[1], in
                the template shown when writing commit messages in
-               linkgit:git-commit[1].
+               linkgit:git-commit[1], and in the help message shown
+               by linkgit:git-checkout[1] when switching branch.
        commitBeforeMerge::
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwriting local changes.
@@ -538,14 +539,14 @@ core.pager::
        `LESS` variable to some other value.  Alternately,
        these settings can be overridden on a project or
        global basis by setting the `core.pager` option.
-       Setting `core.pager` has no affect on the `LESS`
+       Setting `core.pager` has no effect on the `LESS`
        environment variable behaviour above, so if you want
        to override git's default settings this way, you need
        to be explicit.  For example, to disable the S option
        in a backward compatible manner, set `core.pager`
-       to `less -+$LESS -FRX`.  This will be passed to the
-       shell by git, which will translate the final command to
-       `LESS=FRSX less -+FRSX -FRX`.
+       to `less -+S`.  This will be passed to the shell by
+       git, which will translate the final command to
+       `LESS=FRSX less -+S`.
 
 core.whitespace::
        A comma separated list of common whitespace problems to
@@ -962,12 +963,6 @@ difftool.<tool>.cmd::
 difftool.prompt::
        Prompt before each invocation of the diff tool.
 
-diff.wordRegex::
-       A POSIX Extended Regular Expression used to determine what is a "word"
-       when performing word-by-word difference calculations.  Character
-       sequences that match the regular expression are "words", all other
-       characters are *ignorable* whitespace.
-
 fetch.recurseSubmodules::
        This option can be either set to a boolean value or to 'on-demand'.
        Setting it to a boolean changes the behavior of fetch and pull to
@@ -1356,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 67a90a8..4314ad0 100644 (file)
@@ -56,6 +56,10 @@ diff.statGraphWidth::
        Limit the width of the graph part in --stat output. If set, applies
        to all commands generating --stat output except format-patch.
 
+diff.context::
+       Generate diffs with <n> lines of context instead of the default
+       of 3. This value is overridden by the -U option.
+
 diff.external::
        If this config variable is set, diff generation is not
        performed using the internal diff machinery, but using the
@@ -103,6 +107,19 @@ diff.suppressBlankEmpty::
        A boolean to inhibit the standard behavior of printing a space
        before each empty output line. Defaults to false.
 
+diff.submodule::
+       Specify the format in which differences in submodules are
+       shown.  The "log" format lists the commits in the range like
+       linkgit:git-submodule[1] `summary` does.  The "short" format
+       format just shows the names of the commits at the beginning
+       and end of the range.  Defaults to short.
+
+diff.wordRegex::
+       A POSIX Extended Regular Expression used to determine what is a "word"
+       when performing word-by-word difference calculations.  Character
+       sequences that match the regular expression are "words", all other
+       characters are *ignorable* whitespace.
+
 diff.<driver>.command::
        The custom diff driver command.  See linkgit:gitattributes[5]
        for details.
index cf4b216..39f2c50 100644 (file)
@@ -170,7 +170,8 @@ any of those replacements occurred.
        the commits in the range like linkgit:git-submodule[1] `summary` does.
        Omitting the `--submodule` option or specifying `--submodule=short`,
        uses the 'short' format. This format just shows the names of the commits
-       at the beginning and end of the range.
+       at the beginning and end of the range.  Can be tweaked via the
+       `diff.submodule` configuration variable.
 
 --color[=<when>]::
        Show colored diff.
@@ -308,7 +309,11 @@ endif::git-log[]
        index (i.e. amount of addition/deletions compared to the
        file's size). For example, `-M90%` means git should consider a
        delete/add pair to be a rename if more than 90% of the file
-       hasn't changed.
+       hasn't changed.  Without a `%` sign, the number is to be read as
+       a fraction, with a decimal point before it.  I.e., `-M5` becomes
+       0.5, and is thus the same as `-M50%`.  Similarly, `-M05` is
+       the same as `-M5%`.  To limit detection to exact renames, use
+       `-M100%`.
 
 -C[<n>]::
 --find-copies[=<n>]::
index b4d6476..6e98bdf 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 8a2ba37..ec4497e 100644 (file)
@@ -257,7 +257,7 @@ Date:   Sat May 3 11:59:44 2008 -0700
 
     Linux 2.6.26-rc1
 
-:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M      Makefile
+:100644 100644 5cf82581... 4492984e... M      Makefile
 -------------
 
 At this point we can see what the commit does, check it out (if it's
@@ -331,7 +331,7 @@ Date:   Sat May 3 11:59:44 2008 -0700
 
     Linux 2.6.26-rc1
 
-:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M      Makefile
+:100644 100644 5cf82581... 4492984e... M      Makefile
 bisect run success
 -------------
 
index 16a6b0a..bc023cc 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 7958a47..6f04d22 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 6d98ef3..7fefdb0 100644 (file)
@@ -196,9 +196,9 @@ objects from the source repository into a pack in the cloned repository.
        `--no-single-branch` is given to fetch the histories near the
        tips of all branches.
        Further fetches into the resulting repository will only update the
-       remote tracking branch for the branch this option was used for the
+       remote-tracking branch for the branch this option was used for the
        initial cloning.  If the HEAD at the remote did not point at any
-       branch when `--single-branch` clone was made, no remote tracking
+       branch when `--single-branch` clone was made, no remote-tracking
        branch is created.
 
 --recursive::
index 6d5a04c..a221169 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 9594ac8..7bdb039 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
           [--date=<date>] [--cleanup=<mode>] [--status | --no-status]
-          [-i | -o] [--] [<file>...]
+          [-i | -o] [-S[<keyid>]] [--] [<file>...]
 
 DESCRIPTION
 -----------
@@ -109,6 +109,10 @@ OPTIONS
        format. See linkgit:git-status[1] for details. Implies
        `--dry-run`.
 
+--long::
+       When doing a dry-run, give the output in a the long-format.
+       Implies `--dry-run`.
+
 -z::
 --null::
        When showing `short` or `porcelain` status output, terminate
@@ -184,6 +188,11 @@ OPTIONS
        commit log message unmodified.  This option lets you
        further edit the message taken from these sources.
 
+--no-edit::
+       Use the selected commit message without launching an editor.
+       For example, `git commit --amend --no-edit` amends a commit
+       without changing its commit message.
+
 --amend::
        Used to amend the tip of the current branch. Prepare the tree
        object you would want to replace the latest commit as usual
@@ -193,10 +202,6 @@ OPTIONS
        current tip -- if it was a merge, it will have the parents of
        the current tip as parents -- so the current top commit is
        discarded.
-
---no-post-rewrite::
-       Bypass the post-rewrite hook.
-
 +
 --
 It is a rough equivalent for:
@@ -213,6 +218,9 @@ You should understand the implications of rewriting history if you
 amend a commit that has already been published.  (See the "RECOVERING
 FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
 
+--no-post-rewrite::
+       Bypass the post-rewrite hook.
+
 -i::
 --include::
        Before making a commit out of staged contents so far,
@@ -276,6 +284,10 @@ configuration variable documented in linkgit:git-config[1].
        commit message template when using an editor to prepare the
        default commit message.
 
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+       GPG-sign commit.
+
 \--::
        Do not interpret any more arguments as options.
 
index eaea079..9ae2508 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 6695ab3..f059ea9 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.
 
@@ -137,17 +143,19 @@ This option can be used several times to provide several detection regexes.
 -A <author-conv-file>::
        CVS by default uses the Unix username when writing its
        commit logs. Using this option and an author-conv-file
-       in this format
+       maps the name recorded in CVS to author name, e-mail and
+       optional timezone:
 +
 ---------
        exon=Andreas Ericsson <ae@op5.se>
-       spawn=Simon Pawn <spawn@frog-pond.org>
+       spawn=Simon Pawn <spawn@frog-pond.org> America/Chicago
 
 ---------
 +
 'git cvsimport' will make it appear as those authors had
 their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly
-all along.
+all along.  If a timezone is specified, GIT_AUTHOR_DATE will
+have the corresponding offset applied.
 +
 For convenience, this data is saved to `$GIT_DIR/cvs-authors`
 each time the '-A' option is provided and read from that same
@@ -211,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 f8d0819..f8c0601 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 6603a7a..bf1a02a 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
@@ -442,7 +445,9 @@ their syntax.
 ^^^^^^
 The `from` command is used to specify the commit to initialize
 this branch from.  This revision will be the first ancestor of the
-new commit.
+new commit.  The state of the tree built at this commit will begin
+with the state at the `from` commit, and be altered by the content
+modifications in this commit.
 
 Omitting the `from` command in the first commit of a new branch
 will cause fast-import to create that commit with no ancestor. This
@@ -492,7 +497,9 @@ existing value of the branch.
 
 `merge`
 ^^^^^^^
-Includes one additional ancestor commit.  If the `from` command is
+Includes one additional ancestor commit.  The additional ancestry
+link does not change the way the tree state is built at this commit.
+If the `from` command is
 omitted when creating a new branch, the first `merge` commit will be
 the first ancestor of the current commit, and the branch will start
 out with no files.  An unlimited number of `merge` commands per
@@ -558,8 +565,12 @@ A `<path>` string must use UNIX-style directory separators (forward
 slash `/`), may contain any byte other than `LF`, and must not
 start with double quote (`"`).
 
-If an `LF` or double quote must be encoded into `<path>` shell-style
-quoting should be used, e.g. `"path/with\n and \" in it"`.
+A path can use C-style string quoting; this is accepted in all cases
+and mandatory if the filename starts with double quote or contains
+`LF`. In C-style quoting, the complete name should be surrounded with
+double quotes, and any `LF`, backslash, or double quote characters
+must be escaped by preceding them with a backslash (e.g.,
+`"path/with\n, \\ and \" in it"`).
 
 The value of `<path>` must be in canonical form. That is it must not:
 
index 474fa30..8c75120 100644 (file)
@@ -9,7 +9,10 @@ git-fetch-pack - Receive missing objects from another repository
 SYNOPSIS
 --------
 [verse]
-'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]
+'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag]
+                               [--upload-pack=<git-upload-pack>]
+                               [--depth=<n>] [--no-progress]
+                               [-v] [<host>:]<directory> [<refs>...]
 
 DESCRIPTION
 -----------
index db55a4e..f2e08d1 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)`.
 
 
index 6d43f56..259dce4 100644 (file)
@@ -20,7 +20,7 @@ SYNOPSIS
                   [--ignore-if-in-upstream]
                   [--subject-prefix=Subject-Prefix]
                   [--to=<email>] [--cc=<email>]
-                  [--cover-letter] [--quiet]
+                  [--cover-letter] [--quiet] [--notes[=<ref>]]
                   [<common diff options>]
                   [ <since> | <revision range> ]
 
@@ -191,6 +191,18 @@ will want to ensure that threading is disabled for `git send-email`.
        containing the shortlog and the overall diffstat.  You can
        fill in a description in the file before sending it out.
 
+--notes[=<ref>]::
+       Append the notes (see linkgit:git-notes[1]) for the commit
+       after the three-dash line.
++
+The expected use case of this is to write supporting explanation for
+the commit that does not belong to the commit log message proper,
+and include it with the patch submission. While one can simply write
+these explanations after `format-patch` has run but before sending,
+keeping them as git notes allows them to be maintained between versions
+of the patch series (but see the discussion of the `notes.rewrite`
+configuration options in linkgit:git-notes[1] to use this workflow).
+
 --[no]-signature=<signature>::
        Add a signature to each message produced. Per RFC 3676 the signature
        is separated from the body by a line with '-- ' on it. If the
index 20f9228..d34ea3c 100644 (file)
@@ -99,7 +99,7 @@ commit or stash your changes before running 'git merge'.
        more than two parents (affectionately called an Octopus merge).
 +
 If no commit is given from the command line, and if `merge.defaultToUpstream`
-configuration variable is set, merge the remote tracking branches
+configuration variable is set, merge the remote-tracking branches
 that the current branch is configured to use as its upstream.
 See also the configuration section of this manual page.
 
index b95aafa..46ef046 100644 (file)
@@ -39,6 +39,10 @@ message stored in the commit object, the notes are indented like the
 message, after an unindented line saying "Notes (<refname>):" (or
 "Notes:" for `refs/notes/commits`).
 
+Notes can also be added to patches prepared with `git format-patch` by
+using the `--notes` option. Such notes are added as a patch commentary
+after a three dash separator line.
+
 To change which notes are shown by 'git log', see the
 "notes.displayRef" configuration in linkgit:git-log[1].
 
index 22d2580..8b637d3 100644 (file)
@@ -175,7 +175,7 @@ useful if you write an alias or script around 'git push'.
 
 --recurse-submodules=check|on-demand::
        Make sure all submodule commits used by the revisions to be
-       pushed are available on a remote tracking branch. If 'check' is
+       pushed are available on a remote-tracking branch. If 'check' is
        used git will verify that all submodule commits that changed in
        the revisions to be pushed are available on at least one remote
        of the submodule. If any commits are missing the push will be
@@ -286,7 +286,8 @@ leading to commit A.  The history looks like this:
 ----------------
 
 Further suppose that the other person already pushed changes leading to A
-back to the original repository you two obtained the original commit X.
+back to the original repository from which you two obtained the original
+commit X.
 
 The push done by the other person updated the branch that used to point at
 commit X to point at commit A.  It is a fast-forward.
@@ -384,11 +385,23 @@ the ones in the examples below) can be configured as the default for
        A handy way to push the current branch to the same name on the
        remote.
 
-`git push origin master:satellite/master dev:satellite/dev`::
+`git push mothership master:satellite/master dev:satellite/dev`::
        Use the source ref that matches `master` (e.g. `refs/heads/master`)
        to update the ref that matches `satellite/master` (most probably
-       `refs/remotes/satellite/master`) in the `origin` repository, then
+       `refs/remotes/satellite/master`) in the `mothership` repository;
        do the same for `dev` and `satellite/dev`.
++
+This is to emulate `git fetch` run on the `mothership` using `git
+push` that is run in the opposite direction in order to integrate
+the work done on `satellite`, and is often necessary when you can
+only make connection in one way (i.e. satellite can ssh into
+mothership but mothership cannot initiate connection to satellite
+because the latter is behind a firewall or does not run sshd).
++
+After running this `git push` on the `satellite` machine, you would
+ssh into the `mothership` and run `git merge` there to complete the
+emulation of `git pull` that were run on `mothership` to pull changes
+made on `satellite`.
 
 `git push origin HEAD:master`::
        Push the current branch to the remote ref matching `master` in the
index f5836e4..6d696e0 100644 (file)
@@ -35,6 +35,37 @@ 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
 ------------
 
@@ -57,53 +88,17 @@ 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).
 
-'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.
-
-'connect'::
-       For fetching and pushing using git's native packfile protocol
-       that requires a bidirectional, full-duplex connection.
-
-'push'::
-       For listing remote refs and pushing specified objects from the
-       local object store to remote refs.
-
-'fetch'::
-       For listing remote refs and fetching the associated history to
-       the local object store.
-
-'import'::
-       For listing remote refs and fetching the associated history as
-       a fast-import stream.
-
-'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 *:*`.
+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 the
-       packfile protocol.
+       'git upload-pack', etc for communication using
+       git's native packfile protocol. This
+       requires a bidirectional, full-duplex connection.
 +
 Supported commands: 'connect'.
 
@@ -113,16 +108,26 @@ Supported commands: 'connect'.
 +
 Supported commands: 'list for-push', 'push'.
 
-If a helper advertises both 'connect' and 'push', git will use
-'connect' if possible and fall back to 'push' if the helper requests
-so when connecting (see the 'connect' command under COMMANDS).
+'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
-       packfile protocol.
+       git's native packfile protocol. This
+       requires a bidirectional, full-duplex connection.
 +
 Supported commands: 'connect'.
 
@@ -144,14 +149,27 @@ 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.
+       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
+A helper advertising the capability
 `refspec refs/heads/*:refs/svn/origin/branches/*`
-in its capabilities is saying that, when it handles
-`import refs/heads/topic`, the stream it outputs will update the
-`refs/svn/origin/branches/topic` ref.
+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
@@ -159,36 +177,33 @@ advertised with this capability must cover all refs reported by
 the list command.  If no 'refspec' capability is advertised,
 there is an implied `refspec *:*`.
 
-INVOCATION
-----------
+'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.
 
-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.
+'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].
 
-When git encounters a URL of the form '<transport>://<address>', where
-'<transport>' is a protocol that it cannot handle natively, it
-automatically invokes 'git remote-<transport>' with the full URL as
-the second argument. If such a URL is encountered directly on the
-command line, the first argument is the same as the second, and if it
-is encountered in a configured remote, the first argument is the name
-of that remote.
 
-A URL of the form '<transport>::<address>' explicitly instructs git to
-invoke 'git remote-<transport>' with '<address>' as the second
-argument. If such a URL is encountered directly on the command line,
-the first argument is '<address>', and if it is encountered in a
-configured remote, the first argument is the name of that remote.
 
-Additionally, when a configured remote has 'remote.<name>.vcs' set to
-'<transport>', git explicitly invokes 'git remote-<transport>' with
-'<name>' as the first argument. If set, the second argument is
-'remote.<name>.url'; otherwise, the second argument is omitted.
 
 COMMANDS
 --------
@@ -198,9 +213,11 @@ 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 version using the remote
-       helper to understand (unknown mandatory capability is fatal
-       error).
+       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>
@@ -210,9 +227,20 @@ Commands are given by the caller on the helper's standard input, one per line.
        the name; unrecognized attributes are ignored. The list ends
        with a blank line.
 +
-If 'push' is supported this may be called as 'list for-push'
-to obtain the current refs prior to sending one or more 'push'
-commands to the helper.
+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
@@ -222,6 +250,8 @@ commands to the helper.
        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>::
@@ -230,7 +260,7 @@ Supported if the helper has the "option" capability.
        per line, terminated with a blank line.
        Outputs a single blank line when all fetch commands in the
        same batch are complete. Only objects which were reported
-       in the ref list with a sha1 may be fetched this way.
+       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
@@ -286,8 +316,29 @@ 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
@@ -313,10 +364,9 @@ capabilities reported by the helper.
 REF LIST ATTRIBUTES
 -------------------
 
-'for-push'::
-       The caller wants to use the ref list to prepare push
-       commands.  A helper might chose to acquire the ref list by
-       opening a different type of connection to the destination.
+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
@@ -324,6 +374,10 @@ REF LIST ATTRIBUTES
 
 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
index 117e374..978d8da 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git reset' [-q] [<commit>] [--] <paths>...
 'git reset' (--patch | -p) [<commit>] [--] [<paths>...]
-'git reset' (--soft | --mixed | --hard | --merge | --keep) [-q] [<commit>]
+'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
 
 DESCRIPTION
 -----------
@@ -43,11 +43,11 @@ This means that `git reset -p` is the opposite of `git add -p`, i.e.
 you can use it to selectively reset hunks. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
-'git reset' --<mode> [<commit>]::
+'git reset' [<mode>] [<commit>]::
        This form resets the current branch head to <commit> and
        possibly updates the index (resetting it to the tree of <commit>) and
-       the working tree depending on <mode>, which
-       must be one of the following:
+       the working tree depending on <mode>. If <mode> is omitted,
+       defaults to "--mixed". The <mode> must be one of the following:
 +
 --
 --soft::
index 5d31860..262436b 100644 (file)
@@ -134,6 +134,21 @@ use the following command:
 git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached
 ----------------
 
+Submodules
+~~~~~~~~~~
+Only submodules using a gitfile (which means they were cloned
+with a git version 1.7.8 or newer) will be removed from the work
+tree, as their repository lives inside the .git directory of the
+superproject. If a submodule (or one of those nested inside it)
+still uses a .git directory, `git rm` will fail - no matter if forced
+or not - to protect the submodule's history.
+
+A submodule is considered up-to-date when the HEAD is the same as
+recorded in the index, no tracked files are modified and no untracked
+files that aren't ignored are present in the submodules work tree.
+Ignored files are deemed expendable and won't stop a submodule's work
+tree from being removed.
+
 EXAMPLES
 --------
 `git rm Documentation/\*.txt`::
index 3241170..eeb561c 100644 (file)
@@ -126,6 +126,10 @@ The --to option must be repeated for each user you want on the to list.
 +
 Note that no attempts whatsoever are made to validate the encoding.
 
+--compose-encoding=<encoding>::
+       Specify encoding of compose message. Default is the value of the
+       'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
+
 
 Sending
 ~~~~~~~
index afeb4cd..c308e91 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 0aa4e20..711ffe1 100644 (file)
@@ -144,7 +144,7 @@ drop [-q|--quiet] [<stash>]::
 
        Remove a single stashed state from the stash list. When no `<stash>`
        is given, it removes the latest one. i.e. `stash@{0}`, otherwise
-       `<stash>` must a valid stash log reference of the form
+       `<stash>` must be a valid stash log reference of the form
        `stash@{<revision>}`.
 
 create::
index 67e5f53..9f1ef9a 100644 (file)
@@ -38,6 +38,9 @@ OPTIONS
        across git versions and regardless of user configuration. See
        below for details.
 
+--long::
+       Give the output in the long-format. This is the default.
+
 -u[<mode>]::
 --untracked-files[=<mode>]::
        Show untracked files.
index b4683bb..b1de3ba 100644 (file)
@@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules
 SYNOPSIS
 --------
 [verse]
-'git submodule' [--quiet] add [-b branch] [-f|--force]
+'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>]
              [--reference <repository>] [--] <repository> [<path>]
 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
@@ -265,6 +265,11 @@ OPTIONS
        Initialize all submodules for which "git submodule init" has not been
        called so far before updating.
 
+--name::
+       This option is only valid for the add command. It sets the submodule's
+       name to the given string instead of defaulting to its path. The name
+       must be valid as a directory name and may not end with a '/'.
+
 --reference <repository>::
        This option is only valid for add and update commands.  These
        commands sometimes need to clone a remote repository. In this case,
index cfe8d2b..69decb1 100644 (file)
@@ -146,6 +146,13 @@ Skip "branches" and "tags" of first level directories;;
 ------------------------------------------------------------------------
 --
 
+--log-window-size=<n>;;
+    Fetch <n> log entries per request when scanning Subversion history.
+    The default is 100. For very large Subversion repositories, larger
+    values may be needed for 'clone'/'fetch' to complete in reasonable
+    time. But overly large values may lead to higher memory usage and
+    request timeouts.
+
 'clone'::
        Runs 'init' and 'fetch'.  It will automatically create a
        directory based on the basename of the URL passed to it;
@@ -621,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]
@@ -732,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):
@@ -757,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
@@ -823,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
 -------
 
@@ -864,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,
@@ -887,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 981d3a8..ef68ad2 100644 (file)
@@ -3,13 +3,14 @@ git-symbolic-ref(1)
 
 NAME
 ----
-git-symbolic-ref - Read and modify symbolic refs
+git-symbolic-ref - Read, modify and delete symbolic refs
 
 SYNOPSIS
 --------
 [verse]
 'git symbolic-ref' [-m <reason>] <name> <ref>
 'git symbolic-ref' [-q] [--short] <name>
+'git symbolic-ref' --delete [-q] <name>
 
 DESCRIPTION
 -----------
@@ -21,6 +22,9 @@ argument to see which branch your working tree is on.
 Given two arguments, creates or updates a symbolic ref <name> to
 point at the given branch <ref>.
 
+Given `--delete` and an additional argument, deletes the given
+symbolic ref.
+
 A symbolic ref is a regular file that stores a string that
 begins with `ref: refs/`.  For example, your `.git/HEAD` is
 a regular file whose contents is `ref: refs/heads/master`.
@@ -28,6 +32,10 @@ a regular file whose contents is `ref: refs/heads/master`.
 OPTIONS
 -------
 
+-d::
+--delete::
+       Delete the symbolic ref <name>.
+
 -q::
 --quiet::
        Do not issue an error message if the <name> is not a
index 247534e..6470cff 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 4a89a12..c7f211e 100644 (file)
@@ -43,10 +43,21 @@ 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/git.html[documentation for release 1.8.0]
+* link:v1.8.1.3/git.html[documentation for release 1.8.1.3]
 
 * release notes for
-  link:RelNotes/1.8.0.txt[1.8.0],
+  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].
 
 * link:v1.7.12.4/git.html[documentation for release 1.7.12.4]
 
@@ -648,6 +659,7 @@ git so take care if using Cogito etc.
        If the 'GIT_DIR' environment variable is set then it
        specifies a path to use instead of the default `.git`
        for the base of the repository.
+       The '--git-dir' command-line option also sets this value.
 
 'GIT_WORK_TREE'::
        Set the path to the working tree.  The value will not be
@@ -763,6 +775,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',
@@ -867,8 +887,10 @@ Authors
 -------
 Git was started by Linus Torvalds, and is currently maintained by Junio
 C Hamano. Numerous contributions have come from the git mailing list
-<git@vger.kernel.org>. For a more complete list of contributors, see
-http://git-scm.com/about. If you have a clone of git.git itself, the
+<git@vger.kernel.org>.  http://www.ohloh.net/p/git/contributors/summary
+gives you a more complete list of contributors.
+
+If you have a clone of git.git itself, the
 output of linkgit:git-shortlog[1] and linkgit:git-blame[1] can show you
 the authors for specific parts of the project.
 
index ba02d4d..2698f63 100644 (file)
@@ -56,6 +56,7 @@ When more than one pattern matches the path, a later line
 overrides an earlier line.  This overriding is done per
 attribute.  The rules how the pattern matches paths are the
 same as in `.gitignore` files; see linkgit:gitignore[5].
+Unlike `.gitignore`, negative patterns are forbidden.
 
 When deciding what attributes are assigned to a path, git
 consults `$GIT_DIR/info/attributes` file (which has the highest
index 4effd78..ab3e91c 100644 (file)
@@ -18,7 +18,9 @@ working tree, is a text file with a syntax matching the requirements
 of linkgit:git-config[1].
 
 The file contains one subsection per submodule, and the subsection value
-is the name of the submodule. Each submodule section also contains the
+is the name of the submodule. The name is set to the path where the
+submodule has been added unless it was customized with the '--name'
+option of 'git submodule add'. Each submodule section also contains the
 following required keys:
 
 submodule.<name>.path::
index 5c891f1..9f62886 100644 (file)
@@ -93,6 +93,12 @@ refs/remotes/`name`::
        records tip-of-the-tree commit objects of branches copied
        from a remote repository.
 
+refs/replace/`<obj-sha1>`::
+       records the SHA1 of the object that replaces `<obj-sha1>`.
+       This is similar to info/grafts and is internally used and
+       maintained by linkgit:git-replace[1]. Such refs can be exchanged
+       between repositories while grafts are not.
+
 packed-refs::
        records the same information as refs/heads/, refs/tags/,
        and friends record in a more efficient way.  See
index 8823a37..816c791 100644 (file)
@@ -5,36 +5,47 @@ Abstract: Imagine that git development is racing along as usual, when our friend
  neighborhood maintainer is struck down by a wayward bus. Out of the
  hordes of suckers (loyal developers), you have been tricked (chosen) to
  step up as the new maintainer. This howto will show you "how to" do it.
+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).
@@ -58,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.
@@ -73,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
@@ -96,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:
 
@@ -138,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
@@ -158,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:
 
@@ -166,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.
-
-   This step is helped with Meta/cook script (where Meta/ contains
-   a checkout of the 'todo' branch).
+ - Merge maint to master as needed:
 
- - 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
@@ -274,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 74a1c0c..4627ee4 100644 (file)
@@ -8,7 +8,12 @@ Abstract: In this article, JC talks about how he rebases the
  the "master" branch, and how "rebase" works.  Also discussed
  is how this applies to individual developers who sends patches
  upstream.
+Content-type: text/asciidoc
 
+How to rebase from an internal branch
+=====================================
+
+--------------------------------------
 Petr Baudis <pasky@suse.cz> writes:
 
 > Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter
@@ -19,6 +24,7 @@ Petr Baudis <pasky@suse.cz> writes:
 >> > branch to the real branches.
 >>
 > Actually, wouldn't this be also precisely for what StGIT is intended to?
+--------------------------------------
 
 Exactly my feeling.  I was sort of waiting for Catalin to speak
 up.  With its basing philosophical ancestry on quilt, this is
@@ -156,8 +162,3 @@ you continue on starting from the new "master" head, which is
 the #1' commit.
 
 -jc
-
--
-To unsubscribe from this list: send the line "unsubscribe git" in
-the body of a message to majordomo@vger.kernel.org
-More majordomo info at  http://vger.kernel.org/majordomo-info.html
index 48c6756..00c1b45 100644 (file)
@@ -5,6 +5,10 @@ Date: Fri, 26 Aug 2005 18:19:10 -0700
 Abstract: In this how-to article, JC talks about how he
  uses the post-update hook to automate git documentation page
  shown at http://www.kernel.org/pub/software/scm/git/docs/.
+Content-type: text/asciidoc
+
+How to rebuild from update hook
+===============================
 
 The pages under http://www.kernel.org/pub/software/scm/git/docs/
 are built from Documentation/ directory of the git.git project
index 323b513..7484735 100644 (file)
@@ -3,11 +3,17 @@ From: Linus Torvalds <torvalds@linux-foundation.org>
 Subject: corrupt object on git-gc
 Abstract: Some tricks to reconstruct blob objects in order to fix
  a corrupted repository.
+Content-type: text/asciidoc
 
+How to recover a corrupted blob object
+======================================
+
+-----------------------------------------------------------
 On Fri, 9 Nov 2007, Yossi Leybovich wrote:
 >
 > Did not help still the repository look for this object?
 > Any one know how can I track this object and understand which file is it
+-----------------------------------------------------------
 
 So exactly *because* the SHA1 hash is cryptographically secure, the hash
 itself doesn't actually tell you anything, in order to fix a corrupt
@@ -31,19 +37,23 @@ original object, so right now the corrupt object is useless, but it's very
 interesting for the future, in the hope that you can re-create a
 non-corrupt version.
 
+-----------------------------------------------------------
 So:
 
 > ib]$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../
+-----------------------------------------------------------
 
 This is the right thing to do, although it's usually best to save it under
 it's full SHA1 name (you just dropped the "4b" from the result ;).
 
 Let's see what that tells us:
 
+-----------------------------------------------------------
 > ib]$ git-fsck --full
 > broken link from    tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
 >              to    blob 4b9458b3786228369c63936db65827de3cc06200
 > missing blob 4b9458b3786228369c63936db65827de3cc06200
+-----------------------------------------------------------
 
 Ok, I removed the "dangling commit" messages, because they are just
 messages about the fact that you probably have rebased etc, so they're not
index 6fd7119..8a68548 100644 (file)
@@ -7,6 +7,10 @@ Abstract: Sometimes a branch that was already merged to the mainline
  after the offending branch is fixed.
 Message-ID: <7vocz8a6zk.fsf@gitster.siamese.dyndns.org>
 References: <alpine.LFD.2.00.0812181949450.14014@localhost.localdomain>
+Content-type: text/asciidoc
+
+How to revert a faulty merge
+============================
 
 Alan <alan@clueserver.org> said:
 
index 093c656..a59ced8 100644 (file)
@@ -8,8 +8,8 @@ Date: Mon, 29 Aug 2005 21:39:02 -0700
 Content-type: text/asciidoc
 Message-ID: <7voe7g3uop.fsf@assigned-by-dhcp.cox.net>
 
-Reverting an existing commit
-============================
+How to revert an existing commit
+================================
 
 One of the changes I pulled into the 'master' branch turns out to
 break building GIT with GCC 2.95.  While they were well intentioned
index 6d3eb8e..bd10274 100644 (file)
@@ -1,6 +1,10 @@
 From: Junio C Hamano <gitster@pobox.com>
 Subject: Separating topic branches
 Abstract: In this article, JC describes how to separate topic branches.
+Content-type: text/asciidoc
+
+How to separate topic branches
+==============================
 
 This text was originally a footnote to a discussion about the
 behaviour of the git diff commands.
index 622ee5c..a695f01 100644 (file)
@@ -1,6 +1,10 @@
 From: Rutger Nijlunsing <rutger@nospam.com>
 Subject: Setting up a git repository which can be pushed into and pulled from over HTTP(S).
 Date: Thu, 10 Aug 2006 22:00:26 +0200
+Content-type: text/asciidoc
+
+How to setup git server over http
+=================================
 
 Since Apache is one of those packages people like to compile
 themselves while others prefer the bureaucrat's dream Debian, it is
index b7f8d41..a5193b1 100644 (file)
@@ -5,6 +5,10 @@ Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
 Abstract: An example hooks/update script is presented to
  implement repository maintenance policies, such as who can push
  into which branch and who can make a tag.
+Content-type: text/asciidoc
+
+How to use the update hook
+==========================
 
 When your developer runs git-push into the repository,
 git-receive-pack is run (either locally or over ssh) as that
@@ -32,8 +36,7 @@ like this as your hooks/update script.
 [jc: editorial note.  This is a much improved version by Carl
 since I posted the original outline]
 
--- >8 -- beginning of script -- >8 --
-
+----------------------------------------------------
 #!/bin/bash
 
 umask 002
@@ -111,12 +114,12 @@ then
 
       info "Found matching head pattern: '$head_pattern'"
       for user_pattern in $user_patterns; do
-       info "Checking user: '$username' against pattern: '$user_pattern'"
-       matchlen=$(expr "$username" : "$user_pattern")
-       if test "$matchlen" = "${#username}"
-       then
-         grant "Allowing user: '$username' with pattern: '$user_pattern'"
-       fi
+        info "Checking user: '$username' against pattern: '$user_pattern'"
+        matchlen=$(expr "$username" : "$user_pattern")
+        if test "$matchlen" = "${#username}"
+        then
+          grant "Allowing user: '$username' with pattern: '$user_pattern'"
+        fi
       done
       deny "The user is not in the access list for this branch"
     done
@@ -149,13 +152,13 @@ then
 
       info "Found matching head pattern: '$head_pattern'"
       for group_pattern in $group_patterns; do
-       for groupname in $groups; do
-         info "Checking group: '$groupname' against pattern: '$group_pattern'"
-         matchlen=$(expr "$groupname" : "$group_pattern")
-         if test "$matchlen" = "${#groupname}"
-         then
-           grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
-         fi
+        for groupname in $groups; do
+          info "Checking group: '$groupname' against pattern: '$group_pattern'"
+          matchlen=$(expr "$groupname" : "$group_pattern")
+          if test "$matchlen" = "${#groupname}"
+          then
+            grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
+          fi
         done
       done
       deny "None of the user's groups are in the access list for this branch"
@@ -169,24 +172,21 @@ then
 fi
 
 deny >/dev/null "There are no more rules to check.  Denying access"
-
--- >8 -- end of script -- >8 --
+----------------------------------------------------
 
 This uses two files, $GIT_DIR/info/allowed-users and
 allowed-groups, to describe which heads can be pushed into by
 whom.  The format of each file would look like this:
 
-        refs/heads/master      junio
-       +refs/heads/pu          junio
-        refs/heads/cogito$     pasky
-        refs/heads/bw/.*       linus
-        refs/heads/tmp/.*      .*
-        refs/tags/v[0-9].*     junio
+    refs/heads/master   junio
+    +refs/heads/pu      junio
+    refs/heads/cogito$  pasky
+    refs/heads/bw/.*    linus
+    refs/heads/tmp/.*   .*
+    refs/tags/v[0-9].*  junio
 
 With this, Linus can push or create "bw/penguin" or "bw/zebra"
 or "bw/panda" branches, Pasky can do only "cogito", and JC can
 do master and pu branches and make versioned tags.  And anybody
 can do tmp/blah branches. The '+' sign at the pu record means
 that JC can make non-fast-forward pushes on it.
-
-------------
index 4e2f75c..23cdf35 100644 (file)
@@ -1,4 +1,7 @@
+Content-type: text/asciidoc
+
 How to use git-daemon
+=====================
 
 Git can be run in inetd mode and in stand alone mode. But all you want is
 let a coworker pull from you, and therefore need to set up a git server
index 98c0033..00f693b 100644 (file)
@@ -7,8 +7,8 @@ Abstract: Beginning v1.7.9, a contributor can push a signed tag to her
  later validate it.
 Content-type: text/asciidoc
 
-Using signed tag in pull requests
-=================================
+How to use a signed tag in pull requests
+========================================
 
 A typical distributed workflow using Git is for a contributor to fork a
 project, build on it, publish the result to her public repository, and ask
index 288f04e..dd89fca 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
index 861bd6f..9bb4956 100644 (file)
@@ -9,11 +9,11 @@ merge.conflictstyle::
 merge.defaultToUpstream::
        If merge is called without any commit argument, merge the upstream
        branches configured for the current branch by using their last
-       observed values stored in their remote tracking branches.
+       observed values stored in their remote-tracking branches.
        The values of the `branch.<current branch>.merge` that name the
        branches at the remote named by `branch.<current branch>.remote`
        are consulted, and then they are mapped via `remote.<remote>.fetch`
-       to their corresponding remote tracking branches, and the tips of
+       to their corresponding remote-tracking branches, and the tips of
        these tracking branches are merged.
 
 merge.ff::
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 ee49743..1ec14a0 100644 (file)
@@ -79,6 +79,11 @@ if it is part of the log message.
 
        Match the regexp limiting patterns without regard to letters case.
 
+--basic-regexp::
+
+       Consider the limiting patterns to be basic regular expressions;
+       this is the default.
+
 -E::
 --extended-regexp::
 
@@ -91,6 +96,11 @@ if it is part of the log message.
        Consider the limiting patterns to be fixed strings (don't interpret
        pattern as a regular expression).
 
+--perl-regexp::
+
+       Consider the limiting patterns to be Perl-compatible regexp.
+       Requires libpcre to be compiled in.
+
 --remove-empty::
 
        Stop when a given path disappears from the tree.
index 43dbe09..542946b 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.
index 1a79781..a959517 100644 (file)
@@ -53,3 +53,11 @@ Functions
 `argv_array_clear`::
        Free all memory associated with the array and return it to the
        initial, empty state.
+
+`argv_array_detach`::
+       Detach the argv array from the `struct argv_array`, transfering
+       ownership of the allocated array and strings.
+
+`argv_array_free_detached`::
+       Free the memory allocated by a `struct argv_array` that was later
+       detached and is now no longer needed.
index d6fc90a..18142b6 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 af7cc2e..730cfac 100644 (file)
@@ -11,5 +11,3 @@ documents them.
 ////////////////////////////////////////////////////////////////
 // table of contents end
 ////////////////////////////////////////////////////////////////
-
-2007-11-24
index f18b4f4..5d7d7f2 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 95a8bf3..84686b5 100644 (file)
@@ -279,6 +279,22 @@ same behaviour as well.
        Strip whitespace from a buffer. The second parameter controls if
        comments are considered contents to be removed or not.
 
+`strbuf_split_buf`::
+`strbuf_split_str`::
+`strbuf_split_max`::
+`strbuf_split`::
+
+       Split a string or strbuf into a list of strbufs at a specified
+       terminator character.  The returned substrings include the
+       terminator characters.  Some of these functions take a `max`
+       parameter, which, if positive, limits the output to that
+       number of substrings.
+
+`strbuf_list_free`::
+
+       Free a list of strbufs (for example, the return values of the
+       `strbuf_split()` functions).
+
 `launch_editor`::
 
        Launch the user preferred editor to edit a file and fill the buffer
index 94d7a2b..20be348 100644 (file)
@@ -38,7 +38,8 @@ member (you need this if you add things later) and you should set the
   `unsorted_string_list_delete_item`.
 
 . Can remove items not matching a criterion from a sorted or unsorted
-  list using `filter_string_list`.
+  list using `filter_string_list`, or remove empty strings using
+  `string_list_remove_empty_items`.
 
 . Finally it should free the list using `string_list_clear`.
 
@@ -75,13 +76,11 @@ Functions
        to be deleted.  Preserve the order of the items that are
        retained.
 
-`string_list_longest_prefix`::
+`string_list_remove_empty_items`::
 
-       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).
+       Remove any empty strings from the list.  If free_util is true,
+       call free() on the util members of any items that have to be
+       deleted.  Preserve the order of the items that are retained.
 
 `print_string_list`::
 
index 9d25b30..7324154 100644 (file)
@@ -1,7 +1,7 @@
 GIT index format
 ================
 
-= The git index file has the following format
+== The git index file has the following format
 
   All binary numbers are in network byte order. Version 2 is described
   here unless stated otherwise.
@@ -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 1803e64..a7871fb 100644 (file)
@@ -1,7 +1,7 @@
 GIT pack format
 ===============
 
-= pack-*.pack files have the following format:
+== pack-*.pack files have the following format:
 
    - A header appears at the beginning and consists of the following:
 
@@ -34,7 +34,7 @@ GIT pack format
 
   - The trailer records 20-byte SHA1 checksum of all of the above.
 
-= Original (version 1) pack-*.idx files have the following format:
+== Original (version 1) pack-*.idx files have the following format:
 
   - The header consists of 256 4-byte network byte order
     integers.  N-th entry of this table records the number of
@@ -123,8 +123,8 @@ Pack file entry: <+
 
 
 
-= Version 2 pack-*.idx files support packs larger than 4 GiB, and
-  have some other reorganizations.  They have the format:
+== Version 2 pack-*.idx files support packs larger than 4 GiB, and
+   have some other reorganizations.  They have the format:
 
   - A 4-byte magic number '\377tOc' which is an unreasonable
     fanout[0] value.
index d51e20f..f1a51ed 100644 (file)
@@ -117,7 +117,7 @@ A few things to remember here:
 - The repository path is always quoted with single quotes.
 
 Fetching Data From a Server
-===========================
+---------------------------
 
 When one Git repository wants to get data that a second repository
 has, the first can 'fetch' from the second.  This operation determines
@@ -134,7 +134,8 @@ with the object name that each reference currently points to.
 
    $ echo -e -n "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
       nc -v example.com 9418
-   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag
+   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
+               side-band side-band-64k ofs-delta shallow no-progress include-tag
    00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
    003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
    003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
@@ -421,7 +422,7 @@ entire packfile without multiplexing.
 
 
 Pushing Data To a Server
-========================
+------------------------
 
 Pushing data to a server will invoke the 'receive-pack' process on the
 server, which will allow the client to tell it which references it should
index 681efe4..9b5a0bc 100644 (file)
@@ -1,5 +1,5 @@
-git-send-pack
-=============
+Git-send-pack internals
+=======================
 
 Overall operation
 -----------------
index 559263a..0502a54 100644 (file)
@@ -1,6 +1,12 @@
-Def.: Shallow commits do have parents, but not in the shallow
+Shallow commits
+===============
+
+.Definition
+*********************************************************
+Shallow commits do have parents, but not in the shallow
 repo, and therefore grafts are introduced pretending that
 these commits have no parents.
+*********************************************************
 
 The basic idea is to write the SHA1s of shallow commits into
 $GIT_DIR/shallow, and handle its contents like the contents
index 24c8410..c79d4a7 100644 (file)
@@ -74,24 +74,24 @@ For multiple ancestors, a '+' means that this case applies even if
 only one ancestor or remote fits; a '^' means all of the ancestors
 must be the same.
 
-case  ancest    head    remote    result
-----------------------------------------
-1     (empty)+  (empty) (empty)   (empty)
-2ALT  (empty)+  *empty* remote    remote
-2     (empty)^  (empty) remote    no merge
-3ALT  (empty)+  head    *empty*   head
-3     (empty)^  head    (empty)   no merge
-4     (empty)^  head    remote    no merge
-5ALT  *         head    head      head
-6     ancest+   (empty) (empty)   no merge
-8     ancest^   (empty) ancest    no merge
-7     ancest+   (empty) remote    no merge
-10    ancest^   ancest  (empty)   no merge
-9     ancest+   head    (empty)   no merge
-16    anc1/anc2 anc1    anc2      no merge
-13    ancest+   head    ancest    head
-14    ancest+   ancest  remote    remote
-11    ancest+   head    remote    no merge
+ case  ancest    head    remote    result
+ ----------------------------------------
+ 1     (empty)+  (empty) (empty)   (empty)
+ 2ALT  (empty)+  *empty* remote    remote
+ 2     (empty)^  (empty) remote    no merge
+ 3ALT  (empty)+  head    *empty*   head
+ 3     (empty)^  head    (empty)   no merge
+ 4     (empty)^  head    remote    no merge
+ 5ALT  *         head    head      head
+ 6     ancest+   (empty) (empty)   no merge
+ 8     ancest^   (empty) ancest    no merge
+ 7     ancest+   (empty) remote    no merge
+ 10    ancest^   ancest  (empty)   no merge
+ 9     ancest+   head    (empty)   no merge
+ 16    anc1/anc2 anc1    anc2      no merge
+ 13    ancest+   head    ancest    head
+ 14    ancest+   ancest  remote    remote
+ 11    ancest+   head    remote    no merge
 
 Only #2ALT and #3ALT use *empty*, because these are the only cases
 where there can be conflicts that didn't exist before. Note that we
index 85651b5..1b377dc 100644 (file)
@@ -1787,6 +1787,13 @@ $ git format-patch origin
 will produce a numbered series of files in the current directory, one
 for each patch in the current branch but not in origin/HEAD.
 
+`git format-patch` can include an initial "cover letter". You can insert
+commentary on individual patches after the three dash line which
+`format-patch` places after the commit message but before the patch
+itself.  If you use `git notes` to track your cover letter material,
+`git format-patch --notes` will include the commit's notes in a similar
+manner.
+
 You can then import these into your mail client and send them by
 hand.  However, if you have a lot to send at once, you may prefer to
 use the linkgit:git-send-email[1] script to automate the process.
index b09d264..07685f4 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.0
+DEF_VER=v1.8.1.3
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 28f34bd..2dc3b61 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 f69979e..4bb3cf1 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.
 #
@@ -374,7 +378,7 @@ htmldir = share/doc/git-doc
 ETC_GITCONFIG = $(sysconfdir)/gitconfig
 ETC_GITATTRIBUTES = $(sysconfdir)/gitattributes
 lib = lib
-# DESTDIR=
+# DESTDIR =
 pathsep = :
 
 export prefix bindir sharedir sysconfdir gitwebdir localedir
@@ -495,6 +499,7 @@ PROGRAM_OBJS += sh-i18n--envsubst.o
 PROGRAM_OBJS += shell.o
 PROGRAM_OBJS += show-index.o
 PROGRAM_OBJS += upload-pack.o
+PROGRAM_OBJS += remote-testsvn.o
 
 # Binary suffix, set to .exe for Windows builds
 X =
@@ -574,9 +579,9 @@ endif
 export PERL_PATH
 export PYTHON_PATH
 
-LIB_FILE=libgit.a
-XDIFF_LIB=xdiff/lib.a
-VCSSVN_LIB=vcs-svn/lib.a
+LIB_FILE = libgit.a
+XDIFF_LIB = xdiff/lib.a
+VCSSVN_LIB = vcs-svn/lib.a
 
 LIB_H += xdiff/xinclude.h
 LIB_H += xdiff/xmacros.h
@@ -648,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
@@ -745,6 +750,7 @@ LIB_OBJS += editor.o
 LIB_OBJS += entry.o
 LIB_OBJS += environment.o
 LIB_OBJS += exec_cmd.o
+LIB_OBJS += fetch-pack.o
 LIB_OBJS += fsck.o
 LIB_OBJS += gettext.o
 LIB_OBJS += gpg-interface.o
@@ -762,7 +768,8 @@ LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
-LIB_OBJS += merge-file.o
+LIB_OBJS += merge.o
+LIB_OBJS += merge-blobs.o
 LIB_OBJS += merge-recursive.o
 LIB_OBJS += mergesort.o
 LIB_OBJS += name-hash.o
@@ -796,6 +803,7 @@ LIB_OBJS += rerere.o
 LIB_OBJS += resolve-undo.o
 LIB_OBJS += revision.o
 LIB_OBJS += run-command.o
+LIB_OBJS += send-pack.o
 LIB_OBJS += sequencer.o
 LIB_OBJS += server-info.o
 LIB_OBJS += setup.o
@@ -1082,6 +1090,7 @@ ifeq ($(uname_O),Cygwin)
                NO_SYMLINK_HEAD = YesPlease
                NO_IPV6 = YesPlease
                OLD_ICONV = UnfortunatelyYes
+               CYGWIN_V15_WIN32API = YesPlease
        endif
        NO_THREAD_SAFE_PREAD = YesPlease
        NEEDS_LIBICONV = YesPlease
@@ -1134,7 +1143,7 @@ ifeq ($(uname_S),NetBSD)
 endif
 ifeq ($(uname_S),AIX)
        DEFAULT_PAGER = more
-       NO_STRCASESTR=YesPlease
+       NO_STRCASESTR = YesPlease
        NO_MEMMEM = YesPlease
        NO_MKDTEMP = YesPlease
        NO_MKSTEMPS = YesPlease
@@ -1142,7 +1151,7 @@ ifeq ($(uname_S),AIX)
        NO_NSEC = YesPlease
        FREAD_READS_DIRECTORIES = UnfortunatelyYes
        INTERNAL_QSORT = UnfortunatelyYes
-       NEEDS_LIBICONV=YesPlease
+       NEEDS_LIBICONV = YesPlease
        BASIC_CFLAGS += -D_LARGE_FILES
        ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
                NO_PTHREADS = YesPlease
@@ -1150,13 +1159,13 @@ ifeq ($(uname_S),AIX)
                PTHREAD_LIBS = -lpthread
        endif
        ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3)
-               INLINE=''
+               INLINE = ''
        endif
        GIT_TEST_CMP = cmp
 endif
 ifeq ($(uname_S),GNU)
        # GNU/Hurd
-       NO_STRLCPY=YesPlease
+       NO_STRLCPY = YesPlease
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
@@ -1182,9 +1191,9 @@ ifeq ($(uname_S),IRIX)
        NEEDS_LIBGEN = YesPlease
 endif
 ifeq ($(uname_S),IRIX64)
-       NO_SETENV=YesPlease
+       NO_SETENV = YesPlease
        NO_UNSETENV = YesPlease
-       NO_STRCASESTR=YesPlease
+       NO_STRCASESTR = YesPlease
        NO_MEMMEM = YesPlease
        NO_MKSTEMPS = YesPlease
        NO_MKDTEMP = YesPlease
@@ -1198,14 +1207,14 @@ ifeq ($(uname_S),IRIX64)
        NO_REGEX = YesPlease
        NO_FNMATCH_CASEFOLD = YesPlease
        SNPRINTF_RETURNS_BOGUS = YesPlease
-       SHELL_PATH=/usr/gnu/bin/bash
+       SHELL_PATH = /usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
 endif
 ifeq ($(uname_S),HP-UX)
        INLINE = __inline
-       NO_IPV6=YesPlease
-       NO_SETENV=YesPlease
-       NO_STRCASESTR=YesPlease
+       NO_IPV6 = YesPlease
+       NO_SETENV = YesPlease
+       NO_STRCASESTR = YesPlease
        NO_MEMMEM = YesPlease
        NO_MKSTEMPS = YesPlease
        NO_STRLCPY = YesPlease
@@ -1381,6 +1390,10 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
        MKDIR_WO_TRAILING_SLASH = YesPlease
        # RFE 10-120912-4693 submitted to HP NonStop development.
        NO_SETITIMER = UnfortunatelyYes
+       SANE_TOOL_PATH = /usr/coreutils/bin:/usr/local/bin
+       SHELL_PATH = /usr/local/bin/bash
+       # as of H06.25/J06.14, we might better use this
+       #SHELL_PATH = /usr/coreutils/bin/bash
 endif
 ifneq (,$(findstring MINGW,$(uname_S)))
        pathsep = ;
@@ -1428,7 +1441,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        X = .exe
        SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
 ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
-       htmldir=doc/git/html/
+       htmldir = doc/git/html/
        prefix =
        INSTALL = /bin/install
        EXTLIBS += /mingw/lib/libz.a
@@ -1462,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
@@ -1550,7 +1564,7 @@ else
                CURL_LIBCURL = -lcurl
        endif
        ifdef NEEDS_SSL_WITH_CURL
-               CURL_LIBCURL += -lssl
+               CURL_LIBCURL += -lssl
                ifdef NEEDS_CRYPTO_WITH_SSL
                        CURL_LIBCURL += -lcrypto
                endif
@@ -1564,7 +1578,7 @@ else
        REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
        PROGRAM_OBJS += http-fetch.o
        PROGRAMS += $(REMOTE_CURL_NAMES)
-       curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
+       curl_check := $(shell (echo 070908; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "070908"
                ifndef NO_EXPAT
                        PROGRAM_OBJS += http-push.o
@@ -1759,7 +1773,7 @@ ifdef OBJECT_CREATION_USES_RENAMES
 endif
 ifdef NO_STRUCT_ITIMERVAL
        COMPAT_CFLAGS += -DNO_STRUCT_ITIMERVAL
-       NO_SETITIMER=YesPlease
+       NO_SETITIMER = YesPlease
 endif
 ifdef NO_SETITIMER
        COMPAT_CFLAGS += -DNO_SETITIMER
@@ -1889,6 +1903,9 @@ ifdef NO_REGEX
        COMPAT_CFLAGS += -Icompat/regex
        COMPAT_OBJS += compat/regex/regex.o
 endif
+ifdef CYGWIN_V15_WIN32API
+       COMPAT_CFLAGS += -DCYGWIN_V15_WIN32API
+endif
 
 ifdef USE_NED_ALLOCATOR
        COMPAT_CFLAGS += -Icompat/nedmalloc
@@ -1908,15 +1925,15 @@ ifneq (,$(XDL_FAST_HASH))
 endif
 
 ifeq ($(TCLTK_PATH),)
-NO_TCLTK=NoThanks
+NO_TCLTK = NoThanks
 endif
 
 ifeq ($(PERL_PATH),)
-NO_PERL=NoThanks
+NO_PERL = NoThanks
 endif
 
 ifeq ($(PYTHON_PATH),)
-NO_PYTHON=NoThanks
+NO_PYTHON = NoThanks
 endif
 
 QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
@@ -1963,13 +1980,13 @@ PROFILE_DIR := $(CURDIR)
 ifeq ("$(PROFILE)","GEN")
        CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1
        EXTLIBS += -lgcov
-       export CCACHE_DISABLE=t
-       V=1
+       export CCACHE_DISABLE = t
+       V = 1
 else
 ifneq ("$(PROFILE)","")
        CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1
-       export CCACHE_DISABLE=t
-       V=1
+       export CCACHE_DISABLE = t
+       V = 1
 endif
 endif
 
@@ -2233,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 \
@@ -2263,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; \
@@ -2307,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)
@@ -2449,6 +2472,10 @@ git-http-push$X: revision.o http.o http-push.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
+git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
+       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
+       $(VCSSVN_LIB)
+
 $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
        $(QUIET_LNCP)$(RM) $@ && \
        ln $< $@ 2>/dev/null || \
@@ -2620,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)
@@ -2814,7 +2853,7 @@ git.spec: git.spec.in GIT-VERSION-FILE
        sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+
        mv $@+ $@
 
-GIT_TARNAME=git-$(GIT_VERSION)
+GIT_TARNAME = git-$(GIT_VERSION)
 dist: git.spec git-archive$(X) configure
        ./git-archive --format=tar \
                --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
@@ -2895,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 d2690ec..a960ca8 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 2484b38..ce97a3b 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.8.0.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.1.3.txt
\ No newline at end of file
index 05f2d79..40cdc46 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 0ba3f25..d1cce46 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 55f66b4..d3aef53 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 4666404..93e00bb 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);
index 256741d..9e960d5 100644 (file)
@@ -68,3 +68,23 @@ void argv_array_clear(struct argv_array *array)
        }
        argv_array_init(array);
 }
+
+const char **argv_array_detach(struct argv_array *array, int *argc)
+{
+       const char **argv =
+               array->argv == empty_argv || array->argc == 0 ? NULL : array->argv;
+       if (argc)
+               *argc = array->argc;
+       argv_array_init(array);
+       return argv;
+}
+
+void argv_array_free_detached(const char **argv)
+{
+       if (argv) {
+               int i;
+               for (i = 0; argv[i]; i++)
+                       free((char **)argv[i]);
+               free(argv);
+       }
+}
index f4b9866..40248d4 100644 (file)
@@ -18,5 +18,7 @@ void argv_array_pushf(struct argv_array *, const char *fmt, ...);
 void argv_array_pushl(struct argv_array *, ...);
 void argv_array_pop(struct argv_array *);
 void argv_array_clear(struct argv_array *);
+const char **argv_array_detach(struct argv_array *array, int *argc);
+void argv_array_free_detached(const char **argv);
 
 #endif /* ARGV_ARRAY_H */
diff --git a/attr.c b/attr.c
index 887a9ae..8985c5c 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -115,6 +115,13 @@ struct attr_state {
        const char *setto;
 };
 
+struct pattern {
+       const char *pattern;
+       int patternlen;
+       int nowildcardlen;
+       int flags;              /* EXC_FLAG_* */
+};
+
 /*
  * One rule, as from a .gitattributes file.
  *
@@ -131,7 +138,7 @@ struct attr_state {
  */
 struct match_attr {
        union {
-               char *pattern;
+               struct pattern pat;
                struct git_attr *attr;
        } u;
        char is_macro;
@@ -241,9 +248,16 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
        if (is_macro)
                res->u.attr = git_attr_internal(name, namelen);
        else {
-               res->u.pattern = (char *)&(res->state[num_attr]);
-               memcpy(res->u.pattern, name, namelen);
-               res->u.pattern[namelen] = 0;
+               char *p = (char *)&(res->state[num_attr]);
+               memcpy(p, name, namelen);
+               res->u.pat.pattern = p;
+               parse_exclude_pattern(&res->u.pat.pattern,
+                                     &res->u.pat.patternlen,
+                                     &res->u.pat.flags,
+                                     &res->u.pat.nowildcardlen);
+               if (res->u.pat.flags & EXC_FLAG_NEGATIVE)
+                       die(_("Negative patterns are forbidden in git attributes\n"
+                             "Use '\\!' for literal leading exclamation."));
        }
        res->is_macro = is_macro;
        res->num_attr = num_attr;
@@ -277,6 +291,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
 static struct attr_stack {
        struct attr_stack *prev;
        char *origin;
+       size_t originlen;
        unsigned num_matches;
        unsigned alloc;
        struct match_attr **attrs;
@@ -535,6 +550,7 @@ static void bootstrap_attr_stack(void)
        if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
                elem = read_attr(GITATTRIBUTES_FILE, 1);
                elem->origin = xstrdup("");
+               elem->originlen = 0;
                elem->prev = attr_stack;
                attr_stack = elem;
                debug_push(elem);
@@ -548,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
@@ -628,7 +638,7 @@ static void prepare_attr_stack(const char *path)
                        strbuf_addstr(&pathbuf, GITATTRIBUTES_FILE);
                        elem = read_attr(pathbuf.buf, 0);
                        strbuf_setlen(&pathbuf, cp - path);
-                       elem->origin = strbuf_detach(&pathbuf, NULL);
+                       elem->origin = strbuf_detach(&pathbuf, &elem->originlen);
                        elem->prev = attr_stack;
                        attr_stack = elem;
                        debug_push(elem);
@@ -645,28 +655,26 @@ static void prepare_attr_stack(const char *path)
 }
 
 static int path_matches(const char *pathname, int pathlen,
-                       const char *pattern,
+                       const char *basename,
+                       const struct pattern *pat,
                        const char *base, int baselen)
 {
-       if (!strchr(pattern, '/')) {
-               /* match basename */
-               const char *basename = strrchr(pathname, '/');
-               basename = basename ? basename + 1 : pathname;
-               return (fnmatch_icase(pattern, basename, 0) == 0);
-       }
-       /*
-        * match with FNM_PATHNAME; the pattern has base implicitly
-        * in front of it.
-        */
-       if (*pattern == '/')
-               pattern++;
-       if (pathlen < baselen ||
-           (baselen && pathname[baselen] != '/') ||
-           strncmp(pathname, base, baselen))
+       const char *pattern = pat->pattern;
+       int prefix = pat->nowildcardlen;
+
+       if ((pat->flags & EXC_FLAG_MUSTBEDIR) &&
+           ((!pathlen) || (pathname[pathlen-1] != '/')))
                return 0;
-       if (baselen != 0)
-               baselen++;
-       return fnmatch_icase(pattern, pathname + baselen, FNM_PATHNAME) == 0;
+
+       if (pat->flags & EXC_FLAG_NODIR) {
+               return match_basename(basename,
+                                     pathlen - (basename - pathname),
+                                     pattern, prefix,
+                                     pat->patternlen, pat->flags);
+       }
+       return match_pathname(pathname, pathlen,
+                             base, baselen,
+                             pattern, prefix, pat->patternlen, pat->flags);
 }
 
 static int macroexpand_one(int attr_nr, int rem);
@@ -683,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--;
@@ -693,7 +701,8 @@ static int fill_one(const char *what, struct match_attr *a, int rem)
        return rem;
 }
 
-static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
+static int fill(const char *path, int pathlen, const char *basename,
+               struct attr_stack *stk, int rem)
 {
        int i;
        const char *base = stk->origin ? stk->origin : "";
@@ -702,8 +711,8 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
                struct match_attr *a = stk->attrs[i];
                if (a->is_macro)
                        continue;
-               if (path_matches(path, pathlen,
-                                a->u.pattern, base, strlen(base)))
+               if (path_matches(path, pathlen, basename,
+                                &a->u.pat, base, stk->originlen))
                        rem = fill_one("fill", a, rem);
        }
        return rem;
@@ -740,16 +749,29 @@ 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;
+       int i, pathlen, rem, dirlen;
+       const char *basename, *cp, *last_slash = NULL;
+
+       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);
+       prepare_attr_stack(path, dirlen);
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
 
-       pathlen = strlen(path);
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
-               rem = fill(path, pathlen, stk, rem);
+               rem = fill(path, pathlen, basename, stk, rem);
 }
 
 int git_check_attr(const char *path, int num, struct git_attr_check *check)
index 1aad49b..bd1b7b5 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -956,3 +956,41 @@ int bisect_next_all(const char *prefix, int no_checkout)
        return bisect_checkout(bisect_rev_hex, no_checkout);
 }
 
+static inline int log2i(int n)
+{
+       int log2 = 0;
+
+       for (; n > 1; n >>= 1)
+               log2++;
+
+       return log2;
+}
+
+static inline int exp2i(int n)
+{
+       return 1 << n;
+}
+
+/*
+ * Estimate the number of bisect steps left (after the current step)
+ *
+ * For any x between 0 included and 2^n excluded, the probability for
+ * n - 1 steps left looks like:
+ *
+ * P(2^n + x) == (2^n - x) / (2^n + x)
+ *
+ * and P(2^n + x) < 0.5 means 2^n < 3x
+ */
+int estimate_bisect_steps(int all)
+{
+       int n, x, e;
+
+       if (all < 3)
+               return 0;
+
+       n = log2i(all);
+       e = exp2i(n);
+       x = all - e;
+
+       return (e < 3 * x) ? n : n - 1;
+}
index ec3c3ff..2a6c831 100644 (file)
--- a/bisect.h
+++ b/bisect.h
@@ -11,10 +11,6 @@ extern struct commit_list *filter_skipped(struct commit_list *list,
                                          int *count,
                                          int *skipped_first);
 
-extern void print_commit_list(struct commit_list *list,
-                             const char *format_cur,
-                             const char *format_last);
-
 #define BISECT_SHOW_ALL                (1<<0)
 #define REV_LIST_QUIET         (1<<1)
 
index 95116b8..7e7bbd6 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;
 };
 
@@ -37,10 +38,6 @@ int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
                          const unsigned char *from_obj, const unsigned char *to_obj);
 void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
 
-extern int check_pager_config(const char *cmd);
-struct diff_options;
-extern void setup_diff_pager(struct diff_options *);
-
 extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
index 156b3ce..9706ca7 100644 (file)
@@ -2095,7 +2095,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 +2105,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 +2128,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 +2148,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 +2169,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 +3609,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 +3616,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 c27ef21..cfae569 100644 (file)
@@ -1425,7 +1425,7 @@ static void get_commit_info(struct commit *commit,
                            int detailed)
 {
        int len;
-       const char *subject;
+       const char *subject, *encoding;
        char *reencoded, *message;
        static char author_name[1024];
        static char author_mail[1024];
@@ -1446,7 +1446,8 @@ static void get_commit_info(struct commit *commit,
                        die("Cannot read commit %s",
                            sha1_to_hex(commit->object.sha1));
        }
-       reencoded = reencode_commit_message(commit, NULL);
+       encoding = get_log_output_encoding();
+       reencoded = logmsg_reencode(commit, encoding);
        message   = reencoded ? reencoded : commit->buffer;
        ret->author = author_name;
        ret->author_mail = author_mail;
index ffd2684..947c84b 100644 (file)
@@ -154,10 +154,37 @@ static int branch_merged(int kind, const char *name,
        return merged;
 }
 
+static int check_branch_commit(const char *branchname, const char *refname,
+                              unsigned char *sha1, struct commit *head_rev,
+                              int kinds, int force)
+{
+       struct commit *rev = lookup_commit_reference(sha1);
+       if (!rev) {
+               error(_("Couldn't look up commit object for '%s'"), refname);
+               return -1;
+       }
+       if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
+               error(_("The branch '%s' is not fully merged.\n"
+                     "If you are sure you want to delete it, "
+                     "run 'git branch -D %s'."), branchname, branchname);
+               return -1;
+       }
+       return 0;
+}
+
+static void delete_branch_config(const char *branchname)
+{
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_addf(&buf, "branch.%s", branchname);
+       if (git_config_rename_section(buf.buf, NULL) < 0)
+               warning(_("Update of config-file failed"));
+       strbuf_release(&buf);
+}
+
 static int delete_branches(int argc, const char **argv, int force, int kinds,
                           int quiet)
 {
-       struct commit *rev, *head_rev = NULL;
+       struct commit *head_rev = NULL;
        unsigned char sha1[20];
        char *name = NULL;
        const char *fmt;
@@ -187,6 +214,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        die(_("Couldn't look up commit object for HEAD"));
        }
        for (i = 0; i < argc; i++, strbuf_release(&bname)) {
+               const char *target;
+               int flags = 0;
+
                strbuf_branchname(&bname, argv[i]);
                if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
                        error(_("Cannot delete the branch '%s' "
@@ -198,7 +228,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                free(name);
 
                name = mkpathdup(fmt, bname.buf);
-               if (read_ref(name, sha1)) {
+               target = resolve_ref_unsafe(name, sha1, 0, &flags);
+               if (!target ||
+                   (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
                        error(remote_branch
                              ? _("remote branch '%s' not found.")
                              : _("branch '%s' not found."), bname.buf);
@@ -206,40 +238,31 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        continue;
                }
 
-               rev = lookup_commit_reference(sha1);
-               if (!rev) {
-                       error(_("Couldn't look up commit object for '%s'"), name);
-                       ret = 1;
-                       continue;
-               }
-
-               if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
-                       error(_("The branch '%s' is not fully merged.\n"
-                             "If you are sure you want to delete it, "
-                             "run 'git branch -D %s'."), bname.buf, bname.buf);
+               if (!(flags & REF_ISSYMREF) &&
+                   check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
+                                       force)) {
                        ret = 1;
                        continue;
                }
 
-               if (delete_ref(name, sha1, 0)) {
+               if (delete_ref(name, sha1, REF_NODEREF)) {
                        error(remote_branch
                              ? _("Error deleting remote branch '%s'")
                              : _("Error deleting branch '%s'"),
                              bname.buf);
                        ret = 1;
-               } else {
-                       struct strbuf buf = STRBUF_INIT;
-                       if (!quiet)
-                               printf(remote_branch
-                                      ? _("Deleted remote branch %s (was %s).\n")
-                                      : _("Deleted branch %s (was %s).\n"),
-                                      bname.buf,
-                                      find_unique_abbrev(sha1, DEFAULT_ABBREV));
-                       strbuf_addf(&buf, "branch.%s", bname.buf);
-                       if (git_config_rename_section(buf.buf, NULL) < 0)
-                               warning(_("Update of config-file failed"));
-                       strbuf_release(&buf);
+                       continue;
+               }
+               if (!quiet) {
+                       printf(remote_branch
+                              ? _("Deleted remote branch %s (was %s).\n")
+                              : _("Deleted branch %s (was %s).\n"),
+                              bname.buf,
+                              (flags & REF_ISSYMREF)
+                              ? target
+                              : find_unique_abbrev(sha1, DEFAULT_ABBREV));
                }
+               delete_branch_config(bname.buf);
        }
 
        free(name);
@@ -827,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 781295b..a9c1b5a 100644 (file)
@@ -951,6 +951,9 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
        strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
        status = create_symref("HEAD", branch_ref.buf, "checkout -b");
        strbuf_release(&branch_ref);
+       if (!opts->quiet)
+               fprintf(stderr, _("Switched to a new branch '%s'\n"),
+                       opts->new_branch);
        return status;
 }
 
index ec2f75b..8d23a62 100644 (file)
@@ -771,8 +771,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 a17a5df..d6dd3df 100644 (file)
@@ -112,10 +112,11 @@ static const char *only_include_assumed;
 static struct strbuf message = STRBUF_INIT;
 
 static enum {
+       STATUS_FORMAT_NONE = 0,
        STATUS_FORMAT_LONG,
        STATUS_FORMAT_SHORT,
        STATUS_FORMAT_PORCELAIN
-} status_format = STATUS_FORMAT_LONG;
+} status_format;
 
 static int opt_parse_m(const struct option *opt, const char *arg, int unset)
 {
@@ -454,6 +455,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
        case STATUS_FORMAT_PORCELAIN:
                wt_porcelain_print(s);
                break;
+       case STATUS_FORMAT_NONE:
        case STATUS_FORMAT_LONG:
                wt_status_print(s);
                break;
@@ -753,7 +755,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                                ident_shown++ ? "" : "\n",
                                author_ident->buf);
 
-               if (!user_ident_sufficiently_given())
+               if (!committer_ident_sufficiently_given())
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                _("%s"
                                "Committer: %s"),
@@ -1058,9 +1060,13 @@ static int parse_and_validate_options(int argc, const char *argv[],
        if (all && argc > 0)
                die(_("Paths with -a does not make sense."));
 
-       if (s->null_termination && status_format == STATUS_FORMAT_LONG)
-               status_format = STATUS_FORMAT_PORCELAIN;
-       if (status_format != STATUS_FORMAT_LONG)
+       if (s->null_termination) {
+               if (status_format == STATUS_FORMAT_NONE)
+                       status_format = STATUS_FORMAT_PORCELAIN;
+               else if (status_format == STATUS_FORMAT_LONG)
+                       die(_("--long and -z are incompatible"));
+       }
+       if (status_format != STATUS_FORMAT_NONE)
                dry_run = 1;
 
        return argc;
@@ -1159,6 +1165,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                OPT_SET_INT(0, "porcelain", &status_format,
                            N_("machine-readable output"),
                            STATUS_FORMAT_PORCELAIN),
+               OPT_SET_INT(0, "long", &status_format,
+                           N_("show status in long format (default)"),
+                           STATUS_FORMAT_LONG),
                OPT_BOOLEAN('z', "null", &s.null_termination,
                            N_("terminate entries with NUL")),
                { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
@@ -1186,8 +1195,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                             builtin_status_usage, 0);
        finalize_colopts(&s.colopts, -1);
 
-       if (s.null_termination && status_format == STATUS_FORMAT_LONG)
-               status_format = STATUS_FORMAT_PORCELAIN;
+       if (s.null_termination) {
+               if (status_format == STATUS_FORMAT_NONE)
+                       status_format = STATUS_FORMAT_PORCELAIN;
+               else if (status_format == STATUS_FORMAT_LONG)
+                       die(_("--long and -z are incompatible"));
+       }
 
        handle_untracked_files_arg(&s);
        if (show_ignored_in_status)
@@ -1216,6 +1229,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        case STATUS_FORMAT_PORCELAIN:
                wt_porcelain_print(&s);
                break;
+       case STATUS_FORMAT_NONE:
        case STATUS_FORMAT_LONG:
                s.verbose = verbose;
                s.ignore_submodule_arg = ignore_submodule_arg;
@@ -1251,7 +1265,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
                strbuf_addstr(&format, "\n Author: ");
                strbuf_addbuf_percentquote(&format, &author_ident);
        }
-       if (!user_ident_sufficiently_given()) {
+       if (!committer_ident_sufficiently_given()) {
                strbuf_addstr(&format, "\n Committer: ");
                strbuf_addbuf_percentquote(&format, &committer_ident);
                if (advice_implicit_identity) {
@@ -1386,6 +1400,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
                OPT_SET_INT(0, "porcelain", &status_format,
                            N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
+               OPT_SET_INT(0, "long", &status_format,
+                           N_("show status in long format (default)"),
+                           STATUS_FORMAT_LONG),
                OPT_BOOLEAN('z', "null", &s.null_termination,
                            N_("terminate entries with NUL")),
                OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
index e1c33e0..33c9bf9 100644 (file)
@@ -15,7 +15,6 @@ static int show_keys;
 static int use_key_regexp;
 static int do_all;
 static int do_not_match;
-static int seen;
 static char delim = '=';
 static char key_delim = ' ';
 static char term = '\n';
@@ -95,12 +94,19 @@ static int show_all_config(const char *key_, const char *value_, void *cb)
        return 0;
 }
 
-static int show_config(const char *key_, const char *value_, void *cb)
+struct strbuf_list {
+       struct strbuf *items;
+       int nr;
+       int alloc;
+};
+
+static int collect_config(const char *key_, const char *value_, void *cb)
 {
+       struct strbuf_list *values = cb;
+       struct strbuf *buf;
        char value[256];
        const char *vptr = value;
        int must_free_vptr = 0;
-       int dup_error = 0;
        int must_print_delim = 0;
 
        if (!use_key_regexp && strcmp(key_, key))
@@ -111,12 +117,14 @@ static int show_config(const char *key_, const char *value_, void *cb)
            (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
                return 0;
 
+       ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+       buf = &values->items[values->nr++];
+       strbuf_init(buf, 0);
+
        if (show_keys) {
-               printf("%s", key_);
+               strbuf_addstr(buf, key_);
                must_print_delim = 1;
        }
-       if (seen && !do_all)
-               dup_error = 1;
        if (types == TYPE_INT)
                sprintf(value, "%d", git_config_int(key_, value_?value_:""));
        else if (types == TYPE_BOOL)
@@ -129,7 +137,8 @@ static int show_config(const char *key_, const char *value_, void *cb)
                else
                        sprintf(value, "%d", v);
        } else if (types == TYPE_PATH) {
-               git_config_pathname(&vptr, key_, value_);
+               if (git_config_pathname(&vptr, key_, value_) < 0)
+                       return -1;
                must_free_vptr = 1;
        } else if (value_) {
                vptr = value_;
@@ -138,16 +147,12 @@ static int show_config(const char *key_, const char *value_, void *cb)
                vptr = "";
                must_print_delim = 0;
        }
-       seen++;
-       if (dup_error) {
-               error("More than one value for the key %s: %s",
-                               key_, vptr);
-       }
-       else {
-               if (must_print_delim)
-                       printf("%c", key_delim);
-               printf("%s%c", vptr, term);
-       }
+
+       if (must_print_delim)
+               strbuf_addch(buf, key_delim);
+       strbuf_addstr(buf, vptr);
+       strbuf_addch(buf, term);
+
        if (must_free_vptr)
                /* If vptr must be freed, it's a pointer to a
                 * dynamically allocated buffer, it's safe to cast to
@@ -161,19 +166,8 @@ static int show_config(const char *key_, const char *value_, void *cb)
 static int get_value(const char *key_, const char *regex_)
 {
        int ret = CONFIG_GENERIC_ERROR;
-       char *global = NULL, *xdg = NULL, *repo_config = NULL;
-       const char *system_wide = NULL, *local;
-       struct config_include_data inc = CONFIG_INCLUDE_INIT;
-       config_fn_t fn;
-       void *data;
-
-       local = given_config_file;
-       if (!local) {
-               local = repo_config = git_pathdup("config");
-               if (git_config_system())
-                       system_wide = git_etc_gitconfig();
-               home_config_paths(&global, &xdg, "config");
-       }
+       struct strbuf_list values = {NULL};
+       int i;
 
        if (use_key_regexp) {
                char *tl;
@@ -195,7 +189,8 @@ static int get_value(const char *key_, const char *regex_)
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
-                       free(key);
+                       free(key_regexp);
+                       key_regexp = NULL;
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
@@ -215,53 +210,37 @@ static int get_value(const char *key_, const char *regex_)
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
+                       free(regexp);
+                       regexp = NULL;
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        }
 
-       fn = show_config;
-       data = NULL;
-       if (respect_includes) {
-               inc.fn = fn;
-               inc.data = data;
-               fn = git_config_include;
-               data = &inc;
-       }
-
-       if (do_all && system_wide)
-               git_config_from_file(fn, system_wide, data);
-       if (do_all && xdg)
-               git_config_from_file(fn, xdg, data);
-       if (do_all && global)
-               git_config_from_file(fn, global, data);
-       if (do_all)
-               git_config_from_file(fn, local, data);
-       git_config_from_parameters(fn, data);
-       if (!do_all && !seen)
-               git_config_from_file(fn, local, data);
-       if (!do_all && !seen && global)
-               git_config_from_file(fn, global, data);
-       if (!do_all && !seen && xdg)
-               git_config_from_file(fn, xdg, data);
-       if (!do_all && !seen && system_wide)
-               git_config_from_file(fn, system_wide, data);
+       git_config_with_options(collect_config, &values,
+                               given_config_file, respect_includes);
+
+       ret = !values.nr;
 
+       for (i = 0; i < values.nr; i++) {
+               struct strbuf *buf = values.items + i;
+               if (do_all || i == values.nr - 1)
+                       fwrite(buf->buf, 1, buf->len, stdout);
+               strbuf_release(buf);
+       }
+       free(values.items);
+
+free_strings:
        free(key);
+       if (key_regexp) {
+               regfree(key_regexp);
+               free(key_regexp);
+       }
        if (regexp) {
                regfree(regexp);
                free(regexp);
        }
 
-       if (do_all)
-               ret = !seen;
-       else
-               ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
-
-free_strings:
-       free(repo_config);
-       free(global);
-       free(xdg);
        return ret;
 }
 
index 9fe11ed..04c185b 100644 (file)
@@ -144,7 +144,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
        if (!all && !might_be_tag)
                return 0;
 
-       if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
+       if (!peel_ref(path, peeled)) {
                is_tag = !!hashcmp(sha1, peeled);
        } else {
                hashcpy(peeled, sha1);
index 2eb32bd..1c737f7 100644 (file)
@@ -41,9 +41,13 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
        if (rev.pending.nr != 1 ||
            rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
                usage(diff_cache_usage);
-       if (!cached)
+       if (!cached) {
                setup_work_tree();
-       if (read_cache() < 0) {
+               if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
+                       perror("read_cache_preload");
+                       return -1;
+               }
+       } else if (read_cache() < 0) {
                perror("read_cache");
                return -1;
        }
index 9650be2..8c2af6c 100644 (file)
@@ -130,8 +130,6 @@ static int builtin_diff_index(struct rev_info *revs,
                        usage(builtin_diff_usage);
                argv++; argc--;
        }
-       if (!cached)
-               setup_work_tree();
        /*
         * Make sure there is one revision (i.e. pending object),
         * and there is no revision filtering parameters.
@@ -140,8 +138,14 @@ static int builtin_diff_index(struct rev_info *revs,
            revs->max_count != -1 || revs->min_age != -1 ||
            revs->max_age != -1)
                usage(builtin_diff_usage);
-       if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
-               perror("read_cache_preload");
+       if (!cached) {
+               setup_work_tree();
+               if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+                       perror("read_cache_preload");
+                       return -1;
+               }
+       } else if (read_cache() < 0) {
+               perror("read_cache");
                return -1;
        }
        return run_diff_index(revs, cached);
@@ -418,19 +422,3 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                refresh_index_quietly();
        return result;
 }
-
-void setup_diff_pager(struct diff_options *opt)
-{
-       /*
-        * If the user asked for our exit code, then either they want --quiet
-        * or --exit-code. We should definitely not bother with a pager in the
-        * former case, as we will generate no output. Since we still properly
-        * report our exit code even when a pager is run, we _could_ run a
-        * pager with --exit-code. But since we have not done so historically,
-        * and because it is easy to find people oneline advising "git diff
-        * --exit-code" in hooks and other scripts, we do not do so.
-        */
-       if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
-           check_pager_config("diff") != 0)
-               setup_pager();
-}
index e644398..940ae35 100644 (file)
 #include "builtin.h"
-#include "refs.h"
 #include "pkt-line.h"
-#include "commit.h"
-#include "tag.h"
-#include "exec_cmd.h"
-#include "pack.h"
-#include "sideband.h"
 #include "fetch-pack.h"
-#include "remote.h"
-#include "run-command.h"
-#include "transport.h"
-#include "version.h"
-
-static int transfer_unpack_limit = -1;
-static int fetch_unpack_limit = -1;
-static int unpack_limit = 100;
-static int prefer_ofs_delta = 1;
-static int no_done;
-static int fetch_fsck_objects = -1;
-static int transfer_fsck_objects = -1;
-static int agent_supported;
-static struct fetch_pack_args args = {
-       /* .uploadpack = */ "git-upload-pack",
-};
 
 static const char fetch_pack_usage[] =
 "git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
 "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
 "[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
 
-#define COMPLETE       (1U << 0)
-#define COMMON         (1U << 1)
-#define COMMON_REF     (1U << 2)
-#define SEEN           (1U << 3)
-#define POPPED         (1U << 4)
-
-static int marked;
-
-/*
- * After sending this many "have"s if we do not get any new ACK , we
- * give up traversing our history.
- */
-#define MAX_IN_VAIN 256
-
-static struct commit_list *rev_list;
-static int non_common_revs, multi_ack, use_sideband;
-
-static void rev_list_push(struct commit *commit, int mark)
-{
-       if (!(commit->object.flags & mark)) {
-               commit->object.flags |= mark;
-
-               if (!(commit->object.parsed))
-                       if (parse_commit(commit))
-                               return;
-
-               commit_list_insert_by_date(commit, &rev_list);
-
-               if (!(commit->object.flags & COMMON))
-                       non_common_revs++;
-       }
-}
-
-static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct object *o = deref_tag(parse_object(sha1), refname, 0);
-
-       if (o && o->type == OBJ_COMMIT)
-               rev_list_push((struct commit *)o, SEEN);
-
-       return 0;
-}
-
-static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct object *o = deref_tag(parse_object(sha1), refname, 0);
-
-       if (o && o->type == OBJ_COMMIT)
-               clear_commit_marks((struct commit *)o,
-                                  COMMON | COMMON_REF | SEEN | POPPED);
-       return 0;
-}
-
-/*
-   This function marks a rev and its ancestors as common.
-   In some cases, it is desirable to mark only the ancestors (for example
-   when only the server does not yet know that they are common).
-*/
-
-static void mark_common(struct commit *commit,
-               int ancestors_only, int dont_parse)
-{
-       if (commit != NULL && !(commit->object.flags & COMMON)) {
-               struct object *o = (struct object *)commit;
-
-               if (!ancestors_only)
-                       o->flags |= COMMON;
-
-               if (!(o->flags & SEEN))
-                       rev_list_push(commit, SEEN);
-               else {
-                       struct commit_list *parents;
-
-                       if (!ancestors_only && !(o->flags & POPPED))
-                               non_common_revs--;
-                       if (!o->parsed && !dont_parse)
-                               if (parse_commit(commit))
-                                       return;
-
-                       for (parents = commit->parents;
-                                       parents;
-                                       parents = parents->next)
-                               mark_common(parents->item, 0, dont_parse);
-               }
-       }
-}
-
-/*
-  Get the next rev to send, ignoring the common.
-*/
-
-static const unsigned char *get_rev(void)
-{
-       struct commit *commit = NULL;
-
-       while (commit == NULL) {
-               unsigned int mark;
-               struct commit_list *parents;
-
-               if (rev_list == NULL || non_common_revs == 0)
-                       return NULL;
-
-               commit = rev_list->item;
-               if (!commit->object.parsed)
-                       parse_commit(commit);
-               parents = commit->parents;
-
-               commit->object.flags |= POPPED;
-               if (!(commit->object.flags & COMMON))
-                       non_common_revs--;
-
-               if (commit->object.flags & COMMON) {
-                       /* do not send "have", and ignore ancestors */
-                       commit = NULL;
-                       mark = COMMON | SEEN;
-               } else if (commit->object.flags & COMMON_REF)
-                       /* send "have", and ignore ancestors */
-                       mark = COMMON | SEEN;
-               else
-                       /* send "have", also for its ancestors */
-                       mark = SEEN;
-
-               while (parents) {
-                       if (!(parents->item->object.flags & SEEN))
-                               rev_list_push(parents->item, mark);
-                       if (mark & COMMON)
-                               mark_common(parents->item, 1, 0);
-                       parents = parents->next;
-               }
-
-               rev_list = rev_list->next;
-       }
-
-       return commit->object.sha1;
-}
-
-enum ack_type {
-       NAK = 0,
-       ACK,
-       ACK_continue,
-       ACK_common,
-       ACK_ready
-};
-
-static void consume_shallow_list(int fd)
-{
-       if (args.stateless_rpc && args.depth > 0) {
-               /* If we sent a depth we will get back "duplicate"
-                * shallow and unshallow commands every time there
-                * is a block of have lines exchanged.
-                */
-               char line[1000];
-               while (packet_read_line(fd, line, sizeof(line))) {
-                       if (!prefixcmp(line, "shallow "))
-                               continue;
-                       if (!prefixcmp(line, "unshallow "))
-                               continue;
-                       die("git fetch-pack: expected shallow list");
-               }
-       }
-}
-
-struct write_shallow_data {
-       struct strbuf *out;
-       int use_pack_protocol;
-       int count;
-};
-
-static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
-{
-       struct write_shallow_data *data = cb_data;
-       const char *hex = sha1_to_hex(graft->sha1);
-       data->count++;
-       if (data->use_pack_protocol)
-               packet_buf_write(data->out, "shallow %s", hex);
-       else {
-               strbuf_addstr(data->out, hex);
-               strbuf_addch(data->out, '\n');
-       }
-       return 0;
-}
-
-static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
-{
-       struct write_shallow_data data;
-       data.out = out;
-       data.use_pack_protocol = use_pack_protocol;
-       data.count = 0;
-       for_each_commit_graft(write_one_shallow, &data);
-       return data.count;
-}
-
-static enum ack_type get_ack(int fd, unsigned char *result_sha1)
-{
-       static char line[1000];
-       int len = packet_read_line(fd, line, sizeof(line));
-
-       if (!len)
-               die("git fetch-pack: expected ACK/NAK, got EOF");
-       if (line[len-1] == '\n')
-               line[--len] = 0;
-       if (!strcmp(line, "NAK"))
-               return NAK;
-       if (!prefixcmp(line, "ACK ")) {
-               if (!get_sha1_hex(line+4, result_sha1)) {
-                       if (strstr(line+45, "continue"))
-                               return ACK_continue;
-                       if (strstr(line+45, "common"))
-                               return ACK_common;
-                       if (strstr(line+45, "ready"))
-                               return ACK_ready;
-                       return ACK;
-               }
-       }
-       die("git fetch_pack: expected ACK/NAK, got '%s'", line);
-}
-
-static void send_request(int fd, struct strbuf *buf)
-{
-       if (args.stateless_rpc) {
-               send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
-               packet_flush(fd);
-       } else
-               safe_write(fd, buf->buf, buf->len);
-}
-
-static void insert_one_alternate_ref(const struct ref *ref, void *unused)
-{
-       rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
-}
-
-#define INITIAL_FLUSH 16
-#define PIPESAFE_FLUSH 32
-#define LARGE_FLUSH 1024
-
-static int next_flush(int count)
-{
-       int flush_limit = args.stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;
-
-       if (count < flush_limit)
-               count <<= 1;
-       else
-               count += flush_limit;
-       return count;
-}
-
-static int find_common(int fd[2], unsigned char *result_sha1,
-                      struct ref *refs)
-{
-       int fetching;
-       int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
-       const unsigned char *sha1;
-       unsigned in_vain = 0;
-       int got_continue = 0;
-       int got_ready = 0;
-       struct strbuf req_buf = STRBUF_INIT;
-       size_t state_len = 0;
-
-       if (args.stateless_rpc && multi_ack == 1)
-               die("--stateless-rpc requires multi_ack_detailed");
-       if (marked)
-               for_each_ref(clear_marks, NULL);
-       marked = 1;
-
-       for_each_ref(rev_list_insert_ref, NULL);
-       for_each_alternate_ref(insert_one_alternate_ref, NULL);
-
-       fetching = 0;
-       for ( ; refs ; refs = refs->next) {
-               unsigned char *remote = refs->old_sha1;
-               const char *remote_hex;
-               struct object *o;
-
-               /*
-                * If that object is complete (i.e. it is an ancestor of a
-                * local ref), we tell them we have it but do not have to
-                * tell them about its ancestors, which they already know
-                * about.
-                *
-                * We use lookup_object here because we are only
-                * interested in the case we *know* the object is
-                * reachable and we have already scanned it.
-                */
-               if (((o = lookup_object(remote)) != NULL) &&
-                               (o->flags & COMPLETE)) {
-                       continue;
-               }
-
-               remote_hex = sha1_to_hex(remote);
-               if (!fetching) {
-                       struct strbuf c = STRBUF_INIT;
-                       if (multi_ack == 2)     strbuf_addstr(&c, " multi_ack_detailed");
-                       if (multi_ack == 1)     strbuf_addstr(&c, " multi_ack");
-                       if (no_done)            strbuf_addstr(&c, " no-done");
-                       if (use_sideband == 2)  strbuf_addstr(&c, " side-band-64k");
-                       if (use_sideband == 1)  strbuf_addstr(&c, " side-band");
-                       if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack");
-                       if (args.no_progress)   strbuf_addstr(&c, " no-progress");
-                       if (args.include_tag)   strbuf_addstr(&c, " include-tag");
-                       if (prefer_ofs_delta)   strbuf_addstr(&c, " ofs-delta");
-                       if (agent_supported)    strbuf_addf(&c, " agent=%s",
-                                                           git_user_agent_sanitized());
-                       packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
-                       strbuf_release(&c);
-               } else
-                       packet_buf_write(&req_buf, "want %s\n", remote_hex);
-               fetching++;
-       }
-
-       if (!fetching) {
-               strbuf_release(&req_buf);
-               packet_flush(fd[1]);
-               return 1;
-       }
-
-       if (is_repository_shallow())
-               write_shallow_commits(&req_buf, 1);
-       if (args.depth > 0)
-               packet_buf_write(&req_buf, "deepen %d", args.depth);
-       packet_buf_flush(&req_buf);
-       state_len = req_buf.len;
-
-       if (args.depth > 0) {
-               char line[1024];
-               unsigned char sha1[20];
-
-               send_request(fd[1], &req_buf);
-               while (packet_read_line(fd[0], line, sizeof(line))) {
-                       if (!prefixcmp(line, "shallow ")) {
-                               if (get_sha1_hex(line + 8, sha1))
-                                       die("invalid shallow line: %s", line);
-                               register_shallow(sha1);
-                               continue;
-                       }
-                       if (!prefixcmp(line, "unshallow ")) {
-                               if (get_sha1_hex(line + 10, sha1))
-                                       die("invalid unshallow line: %s", line);
-                               if (!lookup_object(sha1))
-                                       die("object not found: %s", line);
-                               /* make sure that it is parsed as shallow */
-                               if (!parse_object(sha1))
-                                       die("error in object: %s", line);
-                               if (unregister_shallow(sha1))
-                                       die("no shallow found: %s", line);
-                               continue;
-                       }
-                       die("expected shallow/unshallow, got %s", line);
-               }
-       } else if (!args.stateless_rpc)
-               send_request(fd[1], &req_buf);
-
-       if (!args.stateless_rpc) {
-               /* If we aren't using the stateless-rpc interface
-                * we don't need to retain the headers.
-                */
-               strbuf_setlen(&req_buf, 0);
-               state_len = 0;
-       }
-
-       flushes = 0;
-       retval = -1;
-       while ((sha1 = get_rev())) {
-               packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1));
-               if (args.verbose)
-                       fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
-               in_vain++;
-               if (flush_at <= ++count) {
-                       int ack;
-
-                       packet_buf_flush(&req_buf);
-                       send_request(fd[1], &req_buf);
-                       strbuf_setlen(&req_buf, state_len);
-                       flushes++;
-                       flush_at = next_flush(count);
-
-                       /*
-                        * We keep one window "ahead" of the other side, and
-                        * will wait for an ACK only on the next one
-                        */
-                       if (!args.stateless_rpc && count == INITIAL_FLUSH)
-                               continue;
-
-                       consume_shallow_list(fd[0]);
-                       do {
-                               ack = get_ack(fd[0], result_sha1);
-                               if (args.verbose && ack)
-                                       fprintf(stderr, "got ack %d %s\n", ack,
-                                                       sha1_to_hex(result_sha1));
-                               switch (ack) {
-                               case ACK:
-                                       flushes = 0;
-                                       multi_ack = 0;
-                                       retval = 0;
-                                       goto done;
-                               case ACK_common:
-                               case ACK_ready:
-                               case ACK_continue: {
-                                       struct commit *commit =
-                                               lookup_commit(result_sha1);
-                                       if (!commit)
-                                               die("invalid commit %s", sha1_to_hex(result_sha1));
-                                       if (args.stateless_rpc
-                                        && ack == ACK_common
-                                        && !(commit->object.flags & COMMON)) {
-                                               /* We need to replay the have for this object
-                                                * on the next RPC request so the peer knows
-                                                * it is in common with us.
-                                                */
-                                               const char *hex = sha1_to_hex(result_sha1);
-                                               packet_buf_write(&req_buf, "have %s\n", hex);
-                                               state_len = req_buf.len;
-                                       }
-                                       mark_common(commit, 0, 1);
-                                       retval = 0;
-                                       in_vain = 0;
-                                       got_continue = 1;
-                                       if (ack == ACK_ready) {
-                                               rev_list = NULL;
-                                               got_ready = 1;
-                                       }
-                                       break;
-                                       }
-                               }
-                       } while (ack);
-                       flushes--;
-                       if (got_continue && MAX_IN_VAIN < in_vain) {
-                               if (args.verbose)
-                                       fprintf(stderr, "giving up\n");
-                               break; /* give up */
-                       }
-               }
-       }
-done:
-       if (!got_ready || !no_done) {
-               packet_buf_write(&req_buf, "done\n");
-               send_request(fd[1], &req_buf);
-       }
-       if (args.verbose)
-               fprintf(stderr, "done\n");
-       if (retval != 0) {
-               multi_ack = 0;
-               flushes++;
-       }
-       strbuf_release(&req_buf);
-
-       consume_shallow_list(fd[0]);
-       while (flushes || multi_ack) {
-               int ack = get_ack(fd[0], result_sha1);
-               if (ack) {
-                       if (args.verbose)
-                               fprintf(stderr, "got ack (%d) %s\n", ack,
-                                       sha1_to_hex(result_sha1));
-                       if (ack == ACK)
-                               return 0;
-                       multi_ack = 1;
-                       continue;
-               }
-               flushes--;
-       }
-       /* it is no error to fetch into a completely empty repo */
-       return count ? retval : 0;
-}
-
-static struct commit_list *complete;
-
-static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct object *o = parse_object(sha1);
-
-       while (o && o->type == OBJ_TAG) {
-               struct tag *t = (struct tag *) o;
-               if (!t->tagged)
-                       break; /* broken repository */
-               o->flags |= COMPLETE;
-               o = parse_object(t->tagged->sha1);
-       }
-       if (o && o->type == OBJ_COMMIT) {
-               struct commit *commit = (struct commit *)o;
-               if (!(commit->object.flags & COMPLETE)) {
-                       commit->object.flags |= COMPLETE;
-                       commit_list_insert_by_date(commit, &complete);
-               }
-       }
-       return 0;
-}
-
-static void mark_recent_complete_commits(unsigned long cutoff)
-{
-       while (complete && cutoff <= complete->item->date) {
-               if (args.verbose)
-                       fprintf(stderr, "Marking %s as complete\n",
-                               sha1_to_hex(complete->item->object.sha1));
-               pop_most_recent_commit(&complete, COMPLETE);
-       }
-}
-
-static int non_matching_ref(struct string_list_item *item, void *unused)
-{
-       if (item->util) {
-               item->util = NULL;
-               return 0;
-       }
-       else
-               return 1;
-}
-
-static void filter_refs(struct ref **refs, struct string_list *sought)
-{
-       struct ref *newlist = NULL;
-       struct ref **newtail = &newlist;
-       struct ref *ref, *next;
-       int sought_pos;
-
-       sought_pos = 0;
-       for (ref = *refs; ref; ref = next) {
-               int keep = 0;
-               next = ref->next;
-               if (!memcmp(ref->name, "refs/", 5) &&
-                   check_refname_format(ref->name + 5, 0))
-                       ; /* trash */
-               else {
-                       while (sought_pos < sought->nr) {
-                               int cmp = strcmp(ref->name, sought->items[sought_pos].string);
-                               if (cmp < 0)
-                                       break; /* definitely do not have it */
-                               else if (cmp == 0) {
-                                       keep = 1; /* definitely have it */
-                                       sought->items[sought_pos++].util = "matched";
-                                       break;
-                               }
-                               else
-                                       sought_pos++; /* might have it; keep looking */
-                       }
-               }
-
-               if (! keep && args.fetch_all &&
-                   (!args.depth || prefixcmp(ref->name, "refs/tags/")))
-                       keep = 1;
-
-               if (keep) {
-                       *newtail = ref;
-                       ref->next = NULL;
-                       newtail = &ref->next;
-               } else {
-                       free(ref);
-               }
-       }
-
-       filter_string_list(sought, 0, non_matching_ref, NULL);
-       *refs = newlist;
-}
-
-static void mark_alternate_complete(const struct ref *ref, void *unused)
-{
-       mark_complete(NULL, ref->old_sha1, 0, NULL);
-}
-
-static int everything_local(struct ref **refs, struct string_list *sought)
-{
-       struct ref *ref;
-       int retval;
-       unsigned long cutoff = 0;
-
-       save_commit_buffer = 0;
-
-       for (ref = *refs; ref; ref = ref->next) {
-               struct object *o;
-
-               o = parse_object(ref->old_sha1);
-               if (!o)
-                       continue;
-
-               /* We already have it -- which may mean that we were
-                * in sync with the other side at some time after
-                * that (it is OK if we guess wrong here).
-                */
-               if (o->type == OBJ_COMMIT) {
-                       struct commit *commit = (struct commit *)o;
-                       if (!cutoff || cutoff < commit->date)
-                               cutoff = commit->date;
-               }
-       }
-
-       if (!args.depth) {
-               for_each_ref(mark_complete, NULL);
-               for_each_alternate_ref(mark_alternate_complete, NULL);
-               if (cutoff)
-                       mark_recent_complete_commits(cutoff);
-       }
-
-       /*
-        * Mark all complete remote refs as common refs.
-        * Don't mark them common yet; the server has to be told so first.
-        */
-       for (ref = *refs; ref; ref = ref->next) {
-               struct object *o = deref_tag(lookup_object(ref->old_sha1),
-                                            NULL, 0);
-
-               if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
-                       continue;
-
-               if (!(o->flags & SEEN)) {
-                       rev_list_push((struct commit *)o, COMMON_REF | SEEN);
-
-                       mark_common((struct commit *)o, 1, 1);
-               }
-       }
-
-       filter_refs(refs, sought);
-
-       for (retval = 1, ref = *refs; ref ; ref = ref->next) {
-               const unsigned char *remote = ref->old_sha1;
-               unsigned char local[20];
-               struct object *o;
-
-               o = lookup_object(remote);
-               if (!o || !(o->flags & COMPLETE)) {
-                       retval = 0;
-                       if (!args.verbose)
-                               continue;
-                       fprintf(stderr,
-                               "want %s (%s)\n", sha1_to_hex(remote),
-                               ref->name);
-                       continue;
-               }
-
-               hashcpy(ref->new_sha1, local);
-               if (!args.verbose)
-                       continue;
-               fprintf(stderr,
-                       "already have %s (%s)\n", sha1_to_hex(remote),
-                       ref->name);
-       }
-       return retval;
-}
-
-static int sideband_demux(int in, int out, void *data)
-{
-       int *xd = data;
-
-       int ret = recv_sideband("fetch-pack", xd[0], out);
-       close(out);
-       return ret;
-}
-
-static int get_pack(int xd[2], char **pack_lockfile)
-{
-       struct async demux;
-       const char *argv[20];
-       char keep_arg[256];
-       char hdr_arg[256];
-       const char **av;
-       int do_keep = args.keep_pack;
-       struct child_process cmd;
-
-       memset(&demux, 0, sizeof(demux));
-       if (use_sideband) {
-               /* xd[] is talking with upload-pack; subprocess reads from
-                * xd[0], spits out band#2 to stderr, and feeds us band#1
-                * through demux->out.
-                */
-               demux.proc = sideband_demux;
-               demux.data = xd;
-               demux.out = -1;
-               if (start_async(&demux))
-                       die("fetch-pack: unable to fork off sideband"
-                           " demultiplexer");
-       }
-       else
-               demux.out = xd[0];
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.argv = argv;
-       av = argv;
-       *hdr_arg = 0;
-       if (!args.keep_pack && unpack_limit) {
-               struct pack_header header;
-
-               if (read_pack_header(demux.out, &header))
-                       die("protocol error: bad pack header");
-               snprintf(hdr_arg, sizeof(hdr_arg),
-                        "--pack_header=%"PRIu32",%"PRIu32,
-                        ntohl(header.hdr_version), ntohl(header.hdr_entries));
-               if (ntohl(header.hdr_entries) < unpack_limit)
-                       do_keep = 0;
-               else
-                       do_keep = 1;
-       }
-
-       if (do_keep) {
-               if (pack_lockfile)
-                       cmd.out = -1;
-               *av++ = "index-pack";
-               *av++ = "--stdin";
-               if (!args.quiet && !args.no_progress)
-                       *av++ = "-v";
-               if (args.use_thin_pack)
-                       *av++ = "--fix-thin";
-               if (args.lock_pack || unpack_limit) {
-                       int s = sprintf(keep_arg,
-                                       "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid());
-                       if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
-                               strcpy(keep_arg + s, "localhost");
-                       *av++ = keep_arg;
-               }
-       }
-       else {
-               *av++ = "unpack-objects";
-               if (args.quiet || args.no_progress)
-                       *av++ = "-q";
-       }
-       if (*hdr_arg)
-               *av++ = hdr_arg;
-       if (fetch_fsck_objects >= 0
-           ? fetch_fsck_objects
-           : transfer_fsck_objects >= 0
-           ? transfer_fsck_objects
-           : 0)
-               *av++ = "--strict";
-       *av++ = NULL;
-
-       cmd.in = demux.out;
-       cmd.git_cmd = 1;
-       if (start_command(&cmd))
-               die("fetch-pack: unable to fork off %s", argv[0]);
-       if (do_keep && pack_lockfile) {
-               *pack_lockfile = index_pack_lockfile(cmd.out);
-               close(cmd.out);
-       }
-
-       if (finish_command(&cmd))
-               die("%s failed", argv[0]);
-       if (use_sideband && finish_async(&demux))
-               die("error in sideband demultiplexer");
-       return 0;
-}
-
-static struct ref *do_fetch_pack(int fd[2],
-               const struct ref *orig_ref,
-               struct string_list *sought,
-               char **pack_lockfile)
-{
-       struct ref *ref = copy_ref_list(orig_ref);
-       unsigned char sha1[20];
-       const char *agent_feature;
-       int agent_len;
-
-       sort_ref_list(&ref, ref_compare_name);
-
-       if (is_repository_shallow() && !server_supports("shallow"))
-               die("Server does not support shallow clients");
-       if (server_supports("multi_ack_detailed")) {
-               if (args.verbose)
-                       fprintf(stderr, "Server supports multi_ack_detailed\n");
-               multi_ack = 2;
-               if (server_supports("no-done")) {
-                       if (args.verbose)
-                               fprintf(stderr, "Server supports no-done\n");
-                       if (args.stateless_rpc)
-                               no_done = 1;
-               }
-       }
-       else if (server_supports("multi_ack")) {
-               if (args.verbose)
-                       fprintf(stderr, "Server supports multi_ack\n");
-               multi_ack = 1;
-       }
-       if (server_supports("side-band-64k")) {
-               if (args.verbose)
-                       fprintf(stderr, "Server supports side-band-64k\n");
-               use_sideband = 2;
-       }
-       else if (server_supports("side-band")) {
-               if (args.verbose)
-                       fprintf(stderr, "Server supports side-band\n");
-               use_sideband = 1;
-       }
-       if (!server_supports("thin-pack"))
-               args.use_thin_pack = 0;
-       if (!server_supports("no-progress"))
-               args.no_progress = 0;
-       if (!server_supports("include-tag"))
-               args.include_tag = 0;
-       if (server_supports("ofs-delta")) {
-               if (args.verbose)
-                       fprintf(stderr, "Server supports ofs-delta\n");
-       } else
-               prefer_ofs_delta = 0;
-
-       if ((agent_feature = server_feature_value("agent", &agent_len))) {
-               agent_supported = 1;
-               if (args.verbose && agent_len)
-                       fprintf(stderr, "Server version is %.*s\n",
-                               agent_len, agent_feature);
-       }
-
-       if (everything_local(&ref, sought)) {
-               packet_flush(fd[1]);
-               goto all_done;
-       }
-       if (find_common(fd, sha1, ref) < 0)
-               if (!args.keep_pack)
-                       /* When cloning, it is not unusual to have
-                        * no common commit.
-                        */
-                       warning("no common commits");
-
-       if (args.stateless_rpc)
-               packet_flush(fd[1]);
-       if (get_pack(fd, pack_lockfile))
-               die("git fetch-pack: fetch failed.");
-
- all_done:
-       return ref;
-}
-
-static int fetch_pack_config(const char *var, const char *value, void *cb)
-{
-       if (strcmp(var, "fetch.unpacklimit") == 0) {
-               fetch_unpack_limit = git_config_int(var, value);
-               return 0;
-       }
-
-       if (strcmp(var, "transfer.unpacklimit") == 0) {
-               transfer_unpack_limit = git_config_int(var, value);
-               return 0;
-       }
-
-       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
-               prefer_ofs_delta = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "fetch.fsckobjects")) {
-               fetch_fsck_objects = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "transfer.fsckobjects")) {
-               transfer_fsck_objects = git_config_bool(var, value);
-               return 0;
-       }
-
-       return git_default_config(var, value, cb);
-}
-
-static struct lock_file lock;
-
-static void fetch_pack_setup(void)
-{
-       static int did_setup;
-       if (did_setup)
-               return;
-       git_config(fetch_pack_config, NULL);
-       if (0 <= transfer_unpack_limit)
-               unpack_limit = transfer_unpack_limit;
-       else if (0 <= fetch_unpack_limit)
-               unpack_limit = fetch_unpack_limit;
-       did_setup = 1;
-}
-
 int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 {
        int i, ret;
@@ -900,9 +17,13 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        char *pack_lockfile = NULL;
        char **pack_lockfile_ptr = NULL;
        struct child_process *conn;
+       struct fetch_pack_args args;
 
        packet_trace_identity("fetch-pack");
 
+       memset(&args, 0, sizeof(args));
+       args.uploadpack = "git-upload-pack";
+
        for (i = 1; i < argc && *argv[i] == '-'; i++) {
                const char *arg = argv[i];
 
@@ -1038,66 +159,3 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 
        return ret;
 }
-
-struct ref *fetch_pack(struct fetch_pack_args *my_args,
-                      int fd[], struct child_process *conn,
-                      const struct ref *ref,
-                      const char *dest,
-                      struct string_list *sought,
-                      char **pack_lockfile)
-{
-       struct stat st;
-       struct ref *ref_cpy;
-
-       fetch_pack_setup();
-       if (&args != my_args)
-               memcpy(&args, my_args, sizeof(args));
-       if (args.depth > 0) {
-               if (stat(git_path("shallow"), &st))
-                       st.st_mtime = 0;
-       }
-
-       if (sought->nr) {
-               sort_string_list(sought);
-               string_list_remove_duplicates(sought, 0);
-       }
-
-       if (!ref) {
-               packet_flush(fd[1]);
-               die("no matching remote head");
-       }
-       ref_cpy = do_fetch_pack(fd, ref, sought, pack_lockfile);
-
-       if (args.depth > 0) {
-               struct cache_time mtime;
-               struct strbuf sb = STRBUF_INIT;
-               char *shallow = git_path("shallow");
-               int fd;
-
-               mtime.sec = st.st_mtime;
-               mtime.nsec = ST_MTIME_NSEC(st);
-               if (stat(shallow, &st)) {
-                       if (mtime.sec)
-                               die("shallow file was removed during fetch");
-               } else if (st.st_mtime != mtime.sec
-#ifdef USE_NSEC
-                               || ST_MTIME_NSEC(st) != mtime.nsec
-#endif
-                         )
-                       die("shallow file was changed during fetch");
-
-               fd = hold_lock_file_for_update(&lock, shallow,
-                                              LOCK_DIE_ON_ERROR);
-               if (!write_shallow_commits(&sb, 0)
-                || write_in_full(fd, sb.buf, sb.len) != sb.len) {
-                       unlink_or_warn(shallow);
-                       rollback_lock_file(&lock);
-               } else {
-                       commit_lock_file(&lock);
-               }
-               strbuf_release(&sb);
-       }
-
-       reprepare_packed_git();
-       return ref_cpy;
-}
index e2e27b2..d9af43c 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 82530a6..0e1b6c8 100644 (file)
@@ -86,7 +86,7 @@ static pthread_cond_t cond_result;
 static int skip_first_line;
 
 static void add_work(struct grep_opt *opt, enum grep_source_type type,
-                    const char *name, const void *id)
+                    const char *name, const char *path, const void *id)
 {
        grep_lock();
 
@@ -94,7 +94,7 @@ static void add_work(struct grep_opt *opt, enum grep_source_type type,
                pthread_cond_wait(&cond_write, &grep_mutex);
        }
 
-       grep_source_init(&todo[todo_end].source, type, name, id);
+       grep_source_init(&todo[todo_end].source, type, name, path, id);
        if (opt->binary != GREP_BINARY_TEXT)
                grep_source_load_driver(&todo[todo_end].source);
        todo[todo_end].done = 0;
@@ -261,103 +261,12 @@ static int wait_all(void)
 }
 #endif
 
-static int parse_pattern_type_arg(const char *opt, const char *arg)
+static int grep_cmd_config(const char *var, const char *value, void *cb)
 {
-       if (!strcmp(arg, "default"))
-               return GREP_PATTERN_TYPE_UNSPECIFIED;
-       else if (!strcmp(arg, "basic"))
-               return GREP_PATTERN_TYPE_BRE;
-       else if (!strcmp(arg, "extended"))
-               return GREP_PATTERN_TYPE_ERE;
-       else if (!strcmp(arg, "fixed"))
-               return GREP_PATTERN_TYPE_FIXED;
-       else if (!strcmp(arg, "perl"))
-               return GREP_PATTERN_TYPE_PCRE;
-       die("bad %s argument: %s", opt, arg);
-}
-
-static void grep_pattern_type_options(const int pattern_type, struct grep_opt *opt)
-{
-       switch (pattern_type) {
-       case GREP_PATTERN_TYPE_UNSPECIFIED:
-               /* fall through */
-
-       case GREP_PATTERN_TYPE_BRE:
-               opt->fixed = 0;
-               opt->pcre = 0;
-               opt->regflags &= ~REG_EXTENDED;
-               break;
-
-       case GREP_PATTERN_TYPE_ERE:
-               opt->fixed = 0;
-               opt->pcre = 0;
-               opt->regflags |= REG_EXTENDED;
-               break;
-
-       case GREP_PATTERN_TYPE_FIXED:
-               opt->fixed = 1;
-               opt->pcre = 0;
-               opt->regflags &= ~REG_EXTENDED;
-               break;
-
-       case GREP_PATTERN_TYPE_PCRE:
-               opt->fixed = 0;
-               opt->pcre = 1;
-               opt->regflags &= ~REG_EXTENDED;
-               break;
-       }
-}
-
-static int grep_config(const char *var, const char *value, void *cb)
-{
-       struct grep_opt *opt = cb;
-       char *color = NULL;
-
-       if (userdiff_config(var, value) < 0)
-               return -1;
-
-       if (!strcmp(var, "grep.extendedregexp")) {
-               if (git_config_bool(var, value))
-                       opt->extended_regexp_option = 1;
-               else
-                       opt->extended_regexp_option = 0;
-               return 0;
-       }
-
-       if (!strcmp(var, "grep.patterntype")) {
-               opt->pattern_type_option = parse_pattern_type_arg(var, value);
-               return 0;
-  }
-
-       if (!strcmp(var, "grep.linenumber")) {
-               opt->linenum = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "color.grep"))
-               opt->color = git_config_colorbool(var, value);
-       else if (!strcmp(var, "color.grep.context"))
-               color = opt->color_context;
-       else if (!strcmp(var, "color.grep.filename"))
-               color = opt->color_filename;
-       else if (!strcmp(var, "color.grep.function"))
-               color = opt->color_function;
-       else if (!strcmp(var, "color.grep.linenumber"))
-               color = opt->color_lineno;
-       else if (!strcmp(var, "color.grep.match"))
-               color = opt->color_match;
-       else if (!strcmp(var, "color.grep.selected"))
-               color = opt->color_selected;
-       else if (!strcmp(var, "color.grep.separator"))
-               color = opt->color_sep;
-       else
-               return git_color_default_config(var, value, cb);
-       if (color) {
-               if (!value)
-                       return config_error_nonbool(var);
-               color_parse(value, var, color);
-       }
-       return 0;
+       int st = grep_config(var, value, cb);
+       if (git_color_default_config(var, value, cb) < 0)
+               st = -1;
+       return st;
 }
 
 static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
@@ -371,7 +280,8 @@ static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type
 }
 
 static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
-                    const char *filename, int tree_name_len)
+                    const char *filename, int tree_name_len,
+                    const char *path)
 {
        struct strbuf pathbuf = STRBUF_INIT;
 
@@ -385,7 +295,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+               add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
                strbuf_release(&pathbuf);
                return 0;
        } else
@@ -394,7 +304,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
                struct grep_source gs;
                int hit;
 
-               grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+               grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
                strbuf_release(&pathbuf);
                hit = grep_source(opt, &gs);
 
@@ -414,7 +324,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               add_work(opt, GREP_SOURCE_FILE, buf.buf, filename);
+               add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
                strbuf_release(&buf);
                return 0;
        } else
@@ -423,7 +333,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
                struct grep_source gs;
                int hit;
 
-               grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename);
+               grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
                strbuf_release(&buf);
                hit = grep_source(opt, &gs);
 
@@ -479,7 +389,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
                if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
                        if (ce_stage(ce))
                                continue;
-                       hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
+                       hit |= grep_sha1(opt, ce->sha1, ce->name, 0, ce->name);
                }
                else
                        hit |= grep_file(opt, ce->name);
@@ -497,7 +407,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 }
 
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
-                    struct tree_desc *tree, struct strbuf *base, int tn_len)
+                    struct tree_desc *tree, struct strbuf *base, int tn_len,
+                    int check_attr)
 {
        int hit = 0;
        enum interesting match = entry_not_interesting;
@@ -518,7 +429,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                strbuf_add(base, entry.path, te_len);
 
                if (S_ISREG(entry.mode)) {
-                       hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
+                       hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len,
+                                        check_attr ? base->buf + tn_len : NULL);
                }
                else if (S_ISDIR(entry.mode)) {
                        enum object_type type;
@@ -533,7 +445,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 
                        strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
-                       hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
+                       hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
+                                        check_attr);
                        free(data);
                }
                strbuf_setlen(base, old_baselen);
@@ -548,7 +461,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                       struct object *obj, const char *name)
 {
        if (obj->type == OBJ_BLOB)
-               return grep_sha1(opt, obj->sha1, name, 0);
+               return grep_sha1(opt, obj->sha1, name, 0, NULL);
        if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
                struct tree_desc tree;
                void *data;
@@ -571,7 +484,8 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                        strbuf_addch(&base, ':');
                }
                init_tree_desc(&tree, data, size);
-               hit = grep_tree(opt, pathspec, &tree, &base, base.len);
+               hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+                               obj->type == OBJ_COMMIT);
                strbuf_release(&base);
                free(data);
                return hit;
@@ -839,27 +753,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(grep_usage, options);
 
-       memset(&opt, 0, sizeof(opt));
-       opt.prefix = prefix;
-       opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
-       opt.relative = 1;
-       opt.pathname = 1;
-       opt.pattern_tail = &opt.pattern_list;
-       opt.header_tail = &opt.header_list;
-       opt.regflags = REG_NEWLINE;
-       opt.max_depth = -1;
-       opt.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
-       opt.extended_regexp_option = 0;
-
-       strcpy(opt.color_context, "");
-       strcpy(opt.color_filename, "");
-       strcpy(opt.color_function, "");
-       strcpy(opt.color_lineno, "");
-       strcpy(opt.color_match, GIT_COLOR_BOLD_RED);
-       strcpy(opt.color_selected, "");
-       strcpy(opt.color_sep, GIT_COLOR_CYAN);
-       opt.color = -1;
-       git_config(grep_config, &opt);
+       init_grep_defaults();
+       git_config(grep_cmd_config, NULL);
+       grep_init(&opt, prefix);
 
        /*
         * If there is no -- then the paths must exist in the working
@@ -875,13 +771,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                             PARSE_OPT_KEEP_DASHDASH |
                             PARSE_OPT_STOP_AT_NON_OPTION |
                             PARSE_OPT_NO_INTERNAL_HELP);
-
-       if (pattern_type_arg != GREP_PATTERN_TYPE_UNSPECIFIED)
-               grep_pattern_type_options(pattern_type_arg, &opt);
-       else if (opt.pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
-               grep_pattern_type_options(opt.pattern_type_option, &opt);
-       else if (opt.extended_regexp_option)
-               grep_pattern_type_options(GREP_PATTERN_TYPE_ERE, &opt);
+       grep_commit_pattern_type(pattern_type_arg, &opt);
 
        if (use_index && !startup_info->have_repository)
                /* die the same way as if we did it at the beginning */
index bd86253..6067a61 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 09cf43e..e7b7db1 100644 (file)
@@ -351,7 +351,8 @@ static int git_log_config(const char *var, const char *value, void *cb)
        }
        if (!prefixcmp(var, "color.decorate."))
                return parse_decorate_color_config(var, 15, value);
-
+       if (grep_config(var, value, cb) < 0)
+               return -1;
        return git_diff_ui_config(var, value, cb);
 }
 
@@ -360,6 +361,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        struct setup_revision_opt opt;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_revisions(&rev, prefix);
@@ -450,6 +452,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
        struct pathspec match_all;
        int i, count, ret = 0;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_pathspec(&match_all, NULL);
@@ -530,6 +533,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        struct setup_revision_opt opt;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_revisions(&rev, prefix);
@@ -552,6 +556,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        struct setup_revision_opt opt;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_revisions(&rev, prefix);
@@ -1121,6 +1126,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        extra_hdr.strdup_strings = 1;
        extra_to.strdup_strings = 1;
        extra_cc.strdup_strings = 1;
+       init_grep_defaults();
        git_config(git_format_config, NULL);
        init_revisions(&rev, prefix);
        rev.commit_format = CMIT_FMT_EMAIL;
index da23140..24a772d 100644 (file)
@@ -483,7 +483,8 @@ static void convert_to_utf8(struct strbuf *line, const char *charset)
 
        if (!charset || !*charset)
                return;
-       if (!strcasecmp(metainfo_charset, charset))
+
+       if (same_encoding(metainfo_charset, charset))
                return;
        out = reencode_string(line->buf, metainfo_charset, charset);
        if (!out)
index 2338832..be5e514 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 897a563..e0d0b7d 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 0ec8f0d..9307e9c 100644 (file)
@@ -628,59 +628,6 @@ static void write_tree_trivial(unsigned char *sha1)
                die(_("git write-tree failed to write a tree"));
 }
 
-static const char *merge_argument(struct commit *commit)
-{
-       if (commit)
-               return sha1_to_hex(commit->object.sha1);
-       else
-               return EMPTY_TREE_SHA1_HEX;
-}
-
-int try_merge_command(const char *strategy, size_t xopts_nr,
-                     const char **xopts, struct commit_list *common,
-                     const char *head_arg, struct commit_list *remotes)
-{
-       const char **args;
-       int i = 0, x = 0, ret;
-       struct commit_list *j;
-       struct strbuf buf = STRBUF_INIT;
-
-       args = xmalloc((4 + xopts_nr + commit_list_count(common) +
-                       commit_list_count(remotes)) * sizeof(char *));
-       strbuf_addf(&buf, "merge-%s", strategy);
-       args[i++] = buf.buf;
-       for (x = 0; x < xopts_nr; x++) {
-               char *s = xmalloc(strlen(xopts[x])+2+1);
-               strcpy(s, "--");
-               strcpy(s+2, xopts[x]);
-               args[i++] = s;
-       }
-       for (j = common; j; j = j->next)
-               args[i++] = xstrdup(merge_argument(j->item));
-       args[i++] = "--";
-       args[i++] = head_arg;
-       for (j = remotes; j; j = j->next)
-               args[i++] = xstrdup(merge_argument(j->item));
-       args[i] = NULL;
-       ret = run_command_v_opt(args, RUN_GIT_CMD);
-       strbuf_release(&buf);
-       i = 1;
-       for (x = 0; x < xopts_nr; x++)
-               free((void *)args[i++]);
-       for (j = common; j; j = j->next)
-               free((void *)args[i++]);
-       i += 2;
-       for (j = remotes; j; j = j->next)
-               free((void *)args[i++]);
-       free(args);
-       discard_cache();
-       if (read_cache() < 0)
-               die(_("failed to read the cache"));
-       resolve_undo_clear();
-
-       return ret;
-}
-
 static int try_merge_strategy(const char *strategy, struct commit_list *common,
                              struct commit_list *remoteheads,
                              struct commit *head, const char *head_arg)
@@ -762,56 +709,6 @@ static int count_unmerged_entries(void)
        return ret;
 }
 
-int checkout_fast_forward(const unsigned char *head, const unsigned char *remote)
-{
-       struct tree *trees[MAX_UNPACK_TREES];
-       struct unpack_trees_options opts;
-       struct tree_desc t[MAX_UNPACK_TREES];
-       int i, fd, nr_trees = 0;
-       struct dir_struct dir;
-       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
-
-       refresh_cache(REFRESH_QUIET);
-
-       fd = hold_locked_index(lock_file, 1);
-
-       memset(&trees, 0, sizeof(trees));
-       memset(&opts, 0, sizeof(opts));
-       memset(&t, 0, sizeof(t));
-       if (overwrite_ignore) {
-               memset(&dir, 0, sizeof(dir));
-               dir.flags |= DIR_SHOW_IGNORED;
-               setup_standard_excludes(&dir);
-               opts.dir = &dir;
-       }
-
-       opts.head_idx = 1;
-       opts.src_index = &the_index;
-       opts.dst_index = &the_index;
-       opts.update = 1;
-       opts.verbose_update = 1;
-       opts.merge = 1;
-       opts.fn = twoway_merge;
-       setup_unpack_trees_porcelain(&opts, "merge");
-
-       trees[nr_trees] = parse_tree_indirect(head);
-       if (!trees[nr_trees++])
-               return -1;
-       trees[nr_trees] = parse_tree_indirect(remote);
-       if (!trees[nr_trees++])
-               return -1;
-       for (i = 0; i < nr_trees; i++) {
-               parse_tree(trees[i]);
-               init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
-       }
-       if (unpack_trees(nr_trees, t, &opts))
-               return -1;
-       if (write_cache(fd, active_cache, active_nr) ||
-               commit_locked_index(lock_file))
-               die(_("unable to write new index file"));
-       return 0;
-}
-
 static void split_merge_strategies(const char *string, struct strategy **list,
                                   int *nr, int *alloc)
 {
@@ -903,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);
@@ -1324,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)
@@ -1424,7 +1323,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                }
 
                if (checkout_fast_forward(head_commit->object.sha1,
-                                         commit->object.sha1)) {
+                                         commit->object.sha1,
+                                         overwrite_ignore)) {
                        ret = 1;
                        goto done;
                }
index 5e14064..f069462 100644 (file)
@@ -2033,7 +2033,6 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo
 
        if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
            !peel_ref(path, peeled)        && /* peelable? */
-           !is_null_sha1(peeled)          && /* annotated tag? */
            locate_object_entry(peeled))      /* object packed? */
                add_object_entry(sha1, OBJ_TAG, NULL, 0);
        return 0;
index f5c6afc..649c3aa 100644 (file)
@@ -301,14 +301,14 @@ static void pll_free(struct pll *l)
  */
 static struct pll * get_permutations(struct pack_list *list, int n)
 {
-       struct pll *subset, *ret = NULL, *new_pll = NULL, *pll;
+       struct pll *subset, *ret = NULL, *new_pll = NULL;
 
        if (list == NULL || pack_list_size(list) < n || n == 0)
                return NULL;
 
        if (n == 1) {
                while (list) {
-                       new_pll = xmalloc(sizeof(pll));
+                       new_pll = xmalloc(sizeof(*new_pll));
                        new_pll->pl = NULL;
                        pack_list_insert(&new_pll->pl, list);
                        new_pll->next = ret;
@@ -321,7 +321,7 @@ static struct pll * get_permutations(struct pack_list *list, int n)
        while (list->next) {
                subset = get_permutations(list->next, n - 1);
                while (subset) {
-                       new_pll = xmalloc(sizeof(pll));
+                       new_pll = xmalloc(sizeof(*new_pll));
                        new_pll->pl = subset->pl;
                        pack_list_insert(&new_pll->pl, list);
                        new_pll->next = ret;
index a5a4b23..937484d 100644 (file)
@@ -39,7 +39,7 @@ static const char * const builtin_remote_rm_usage[] = {
 };
 
 static const char * const builtin_remote_sethead_usage[] = {
-       N_("git remote set-head <name> (-a | -d | <branch>])"),
+       N_("git remote set-head <name> (-a | -d | <branch>)"),
        NULL
 };
 
index e3aaf70..398ccd5 100644 (file)
@@ -46,24 +46,27 @@ typedef int (*each_replace_name_fn)(const char *name, const char *ref,
 
 static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
 {
-       const char **p;
+       const char **p, *full_hex;
        char ref[PATH_MAX];
        int had_error = 0;
        unsigned char sha1[20];
 
        for (p = argv; *p; p++) {
-               if (snprintf(ref, sizeof(ref), "refs/replace/%s", *p)
-                                       >= sizeof(ref)) {
-                       error("replace ref name too long: %.*s...", 50, *p);
+               if (get_sha1(*p, sha1)) {
+                       error("Failed to resolve '%s' as a valid ref.", *p);
                        had_error = 1;
                        continue;
                }
+               full_hex = sha1_to_hex(sha1);
+               snprintf(ref, sizeof(ref), "refs/replace/%s", full_hex);
+               /* read_ref() may reuse the buffer */
+               full_hex = ref + strlen("refs/replace/");
                if (read_ref(ref, sha1)) {
-                       error("replace ref '%s' not found.", *p);
+                       error("replace ref '%s' not found.", full_hex);
                        had_error = 1;
                        continue;
                }
-               if (fn(*p, ref, sha1))
+               if (fn(full_hex, ref, sha1))
                        had_error = 1;
        }
        return had_error;
index ff5a383..67701be 100644 (file)
@@ -201,55 +201,6 @@ static void show_edge(struct commit *commit)
        printf("-%s\n", sha1_to_hex(commit->object.sha1));
 }
 
-static inline int log2i(int n)
-{
-       int log2 = 0;
-
-       for (; n > 1; n >>= 1)
-               log2++;
-
-       return log2;
-}
-
-static inline int exp2i(int n)
-{
-       return 1 << n;
-}
-
-/*
- * Estimate the number of bisect steps left (after the current step)
- *
- * For any x between 0 included and 2^n excluded, the probability for
- * n - 1 steps left looks like:
- *
- * P(2^n + x) == (2^n - x) / (2^n + x)
- *
- * and P(2^n + x) < 0.5 means 2^n < 3x
- */
-int estimate_bisect_steps(int all)
-{
-       int n, x, e;
-
-       if (all < 3)
-               return 0;
-
-       n = log2i(all);
-       e = exp2i(n);
-       x = all - e;
-
-       return (e < 3 * x) ? n : n - 1;
-}
-
-void print_commit_list(struct commit_list *list,
-                      const char *format_cur,
-                      const char *format_last)
-{
-       for ( ; list; list = list->next) {
-               const char *format = list->next ? format_cur : format_last;
-               printf(format, sha1_to_hex(list->item->object.sha1));
-       }
-}
-
 static void print_var_str(const char *var, const char *val)
 {
        printf("%s='%s'\n", var, val);
index b384c4c..dabfcf6 100644 (file)
@@ -9,6 +9,7 @@
 #include "cache-tree.h"
 #include "tree-walk.h"
 #include "parse-options.h"
+#include "submodule.h"
 
 static const char * const builtin_rm_usage[] = {
        N_("git rm [options] [--] <file>..."),
@@ -17,9 +18,58 @@ static const char * const builtin_rm_usage[] = {
 
 static struct {
        int nr, alloc;
-       const char **name;
+       struct {
+               const char *name;
+               char is_submodule;
+       } *entry;
 } list;
 
+static int get_ours_cache_pos(const char *path, int pos)
+{
+       int i = -pos - 1;
+
+       while ((i < active_nr) && !strcmp(active_cache[i]->name, path)) {
+               if (ce_stage(active_cache[i]) == 2)
+                       return i;
+               i++;
+       }
+       return -1;
+}
+
+static int check_submodules_use_gitfiles(void)
+{
+       int i;
+       int errs = 0;
+
+       for (i = 0; i < list.nr; i++) {
+               const char *name = list.entry[i].name;
+               int pos;
+               struct cache_entry *ce;
+               struct stat st;
+
+               pos = cache_name_pos(name, strlen(name));
+               if (pos < 0) {
+                       pos = get_ours_cache_pos(name, pos);
+                       if (pos < 0)
+                               continue;
+               }
+               ce = active_cache[pos];
+
+               if (!S_ISGITLINK(ce->ce_mode) ||
+                   (lstat(ce->name, &st) < 0) ||
+                   is_empty_dir(name))
+                       continue;
+
+               if (!submodule_uses_gitfile(name))
+                       errs = error(_("submodule '%s' (or one of its nested "
+                                    "submodules) uses a .git directory\n"
+                                    "(use 'rm -rf' if you really want to remove "
+                                    "it including all of its history)"), name);
+       }
+
+       return errs;
+}
+
 static int check_local_mod(unsigned char *head, int index_only)
 {
        /*
@@ -37,15 +87,26 @@ static int check_local_mod(unsigned char *head, int index_only)
                struct stat st;
                int pos;
                struct cache_entry *ce;
-               const char *name = list.name[i];
+               const char *name = list.entry[i].name;
                unsigned char sha1[20];
                unsigned mode;
                int local_changes = 0;
                int staged_changes = 0;
 
                pos = cache_name_pos(name, strlen(name));
-               if (pos < 0)
-                       continue; /* removing unmerged entry */
+               if (pos < 0) {
+                       /*
+                        * Skip unmerged entries except for populated submodules
+                        * that could lose history when removed.
+                        */
+                       pos = get_ours_cache_pos(name, pos);
+                       if (pos < 0)
+                               continue;
+
+                       if (!S_ISGITLINK(active_cache[pos]->ce_mode) ||
+                           is_empty_dir(name))
+                               continue;
+               }
                ce = active_cache[pos];
 
                if (lstat(ce->name, &st) < 0) {
@@ -58,9 +119,10 @@ static int check_local_mod(unsigned char *head, int index_only)
                        /* if a file was removed and it is now a
                         * directory, that is the same as ENOENT as
                         * far as git is concerned; we do not track
-                        * directories.
+                        * directories unless they are submodules.
                         */
-                       continue;
+                       if (!S_ISGITLINK(ce->ce_mode))
+                               continue;
                }
 
                /*
@@ -80,8 +142,11 @@ static int check_local_mod(unsigned char *head, int index_only)
 
                /*
                 * Is the index different from the file in the work tree?
+                * If it's a submodule, is its work tree modified?
                 */
-               if (ce_match_stat(ce, &st, 0))
+               if (ce_match_stat(ce, &st, 0) ||
+                   (S_ISGITLINK(ce->ce_mode) &&
+                    !ok_to_remove_submodule(ce->name)))
                        local_changes = 1;
 
                /*
@@ -115,10 +180,18 @@ static int check_local_mod(unsigned char *head, int index_only)
                                errs = error(_("'%s' has changes staged in the index\n"
                                             "(use --cached to keep the file, "
                                             "or -f to force removal)"), name);
-                       if (local_changes)
-                               errs = error(_("'%s' has local modifications\n"
-                                            "(use --cached to keep the file, "
-                                            "or -f to force removal)"), name);
+                       if (local_changes) {
+                               if (S_ISGITLINK(ce->ce_mode) &&
+                                   !submodule_uses_gitfile(name)) {
+                                       errs = error(_("submodule '%s' (or one of its nested "
+                                                    "submodules) uses a .git directory\n"
+                                                    "(use 'rm -rf' if you really want to remove "
+                                                    "it including all of its history)"), name);
+                               } else
+                                       errs = error(_("'%s' has local modifications\n"
+                                                    "(use --cached to keep the file, "
+                                                    "or -f to force removal)"), name);
+                       }
                }
        }
        return errs;
@@ -161,6 +234,21 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        if (read_cache() < 0)
                die(_("index file corrupt"));
 
+       /*
+        * Drop trailing directory separators from directories so we'll find
+        * submodules in the index.
+        */
+       for (i = 0; i < argc; i++) {
+               size_t pathlen = strlen(argv[i]);
+               if (pathlen && is_dir_sep(argv[i][pathlen - 1]) &&
+                   is_directory(argv[i])) {
+                       do {
+                               pathlen--;
+                       } while (pathlen && is_dir_sep(argv[i][pathlen - 1]));
+                       argv[i] = xmemdupz(argv[i], pathlen);
+               }
+       }
+
        pathspec = get_pathspec(prefix, argv);
        refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL);
 
@@ -173,8 +261,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                struct cache_entry *ce = active_cache[i];
                if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
                        continue;
-               ALLOC_GROW(list.name, list.nr + 1, list.alloc);
-               list.name[list.nr++] = ce->name;
+               ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
+               list.entry[list.nr].name = ce->name;
+               list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode);
        }
 
        if (pathspec) {
@@ -215,6 +304,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                        hashclr(sha1);
                if (check_local_mod(sha1, index_only))
                        exit(1);
+       } else if (!index_only) {
+               if (check_submodules_use_gitfiles())
+                       exit(1);
        }
 
        /*
@@ -222,7 +314,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
         * the index unless all of them succeed.
         */
        for (i = 0; i < list.nr; i++) {
-               const char *path = list.name[i];
+               const char *path = list.entry[i].name;
                if (!quiet)
                        printf("rm '%s'\n", path);
 
@@ -244,7 +336,25 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        if (!index_only) {
                int removed = 0;
                for (i = 0; i < list.nr; i++) {
-                       const char *path = list.name[i];
+                       const char *path = list.entry[i].name;
+                       if (list.entry[i].is_submodule) {
+                               if (is_empty_dir(path)) {
+                                       if (!rmdir(path)) {
+                                               removed = 1;
+                                               continue;
+                                       }
+                               } else {
+                                       struct strbuf buf = STRBUF_INIT;
+                                       strbuf_addstr(&buf, path);
+                                       if (!remove_dir_recursively(&buf, 0)) {
+                                               removed = 1;
+                                               strbuf_release(&buf);
+                                               continue;
+                                       }
+                                       strbuf_release(&buf);
+                                       /* Fallthrough and let remove_path() fail. */
+                               }
+                       }
                        if (!remove_path(path)) {
                                removed = 1;
                                continue;
index 7d05064..d342013 100644 (file)
@@ -16,164 +16,6 @@ static const char send_pack_usage[] =
 
 static struct send_pack_args args;
 
-static int feed_object(const unsigned char *sha1, int fd, int negative)
-{
-       char buf[42];
-
-       if (negative && !has_sha1_file(sha1))
-               return 1;
-
-       memcpy(buf + negative, sha1_to_hex(sha1), 40);
-       if (negative)
-               buf[0] = '^';
-       buf[40 + negative] = '\n';
-       return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
-}
-
-/*
- * Make a pack stream and spit it out into file descriptor fd
- */
-static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
-{
-       /*
-        * The child becomes pack-objects --revs; we feed
-        * the revision parameters to it via its stdin and
-        * let its stdout go back to the other end.
-        */
-       const char *argv[] = {
-               "pack-objects",
-               "--all-progress-implied",
-               "--revs",
-               "--stdout",
-               NULL,
-               NULL,
-               NULL,
-               NULL,
-               NULL,
-       };
-       struct child_process po;
-       int i;
-
-       i = 4;
-       if (args->use_thin_pack)
-               argv[i++] = "--thin";
-       if (args->use_ofs_delta)
-               argv[i++] = "--delta-base-offset";
-       if (args->quiet || !args->progress)
-               argv[i++] = "-q";
-       if (args->progress)
-               argv[i++] = "--progress";
-       memset(&po, 0, sizeof(po));
-       po.argv = argv;
-       po.in = -1;
-       po.out = args->stateless_rpc ? -1 : fd;
-       po.git_cmd = 1;
-       if (start_command(&po))
-               die_errno("git pack-objects failed");
-
-       /*
-        * We feed the pack-objects we just spawned with revision
-        * parameters by writing to the pipe.
-        */
-       for (i = 0; i < extra->nr; i++)
-               if (!feed_object(extra->array[i], po.in, 1))
-                       break;
-
-       while (refs) {
-               if (!is_null_sha1(refs->old_sha1) &&
-                   !feed_object(refs->old_sha1, po.in, 1))
-                       break;
-               if (!is_null_sha1(refs->new_sha1) &&
-                   !feed_object(refs->new_sha1, po.in, 0))
-                       break;
-               refs = refs->next;
-       }
-
-       close(po.in);
-
-       if (args->stateless_rpc) {
-               char *buf = xmalloc(LARGE_PACKET_MAX);
-               while (1) {
-                       ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
-                       if (n <= 0)
-                               break;
-                       send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
-               }
-               free(buf);
-               close(po.out);
-               po.out = -1;
-       }
-
-       if (finish_command(&po))
-               return -1;
-       return 0;
-}
-
-static int receive_status(int in, struct ref *refs)
-{
-       struct ref *hint;
-       char line[1000];
-       int ret = 0;
-       int len = packet_read_line(in, line, sizeof(line));
-       if (len < 10 || memcmp(line, "unpack ", 7))
-               return error("did not receive remote status");
-       if (memcmp(line, "unpack ok\n", 10)) {
-               char *p = line + strlen(line) - 1;
-               if (*p == '\n')
-                       *p = '\0';
-               error("unpack failed: %s", line + 7);
-               ret = -1;
-       }
-       hint = NULL;
-       while (1) {
-               char *refname;
-               char *msg;
-               len = packet_read_line(in, line, sizeof(line));
-               if (!len)
-                       break;
-               if (len < 3 ||
-                   (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
-                       fprintf(stderr, "protocol error: %s\n", line);
-                       ret = -1;
-                       break;
-               }
-
-               line[strlen(line)-1] = '\0';
-               refname = line + 3;
-               msg = strchr(refname, ' ');
-               if (msg)
-                       *msg++ = '\0';
-
-               /* first try searching at our hint, falling back to all refs */
-               if (hint)
-                       hint = find_ref_by_name(hint, refname);
-               if (!hint)
-                       hint = find_ref_by_name(refs, refname);
-               if (!hint) {
-                       warning("remote reported status on unknown ref: %s",
-                                       refname);
-                       continue;
-               }
-               if (hint->status != REF_STATUS_EXPECTING_REPORT) {
-                       warning("remote reported status on unexpected ref: %s",
-                                       refname);
-                       continue;
-               }
-
-               if (line[0] == 'o' && line[1] == 'k')
-                       hint->status = REF_STATUS_OK;
-               else {
-                       hint->status = REF_STATUS_REMOTE_REJECT;
-                       ret = -1;
-               }
-               if (msg)
-                       hint->remote_status = xstrdup(msg);
-               /* start our next search from the next ref */
-               hint = hint->next;
-       }
-       return ret;
-}
-
 static void print_helper_status(struct ref *ref)
 {
        struct strbuf buf = STRBUF_INIT;
@@ -227,181 +69,6 @@ static void print_helper_status(struct ref *ref)
        strbuf_release(&buf);
 }
 
-static int sideband_demux(int in, int out, void *data)
-{
-       int *fd = data, ret;
-#ifdef NO_PTHREADS
-       close(fd[1]);
-#endif
-       ret = recv_sideband("send-pack", fd[0], out);
-       close(out);
-       return ret;
-}
-
-int send_pack(struct send_pack_args *args,
-             int fd[], struct child_process *conn,
-             struct ref *remote_refs,
-             struct extra_have_objects *extra_have)
-{
-       int in = fd[0];
-       int out = fd[1];
-       struct strbuf req_buf = STRBUF_INIT;
-       struct ref *ref;
-       int new_refs;
-       int allow_deleting_refs = 0;
-       int status_report = 0;
-       int use_sideband = 0;
-       int quiet_supported = 0;
-       int agent_supported = 0;
-       unsigned cmds_sent = 0;
-       int ret;
-       struct async demux;
-
-       /* Does the other end support the reporting? */
-       if (server_supports("report-status"))
-               status_report = 1;
-       if (server_supports("delete-refs"))
-               allow_deleting_refs = 1;
-       if (server_supports("ofs-delta"))
-               args->use_ofs_delta = 1;
-       if (server_supports("side-band-64k"))
-               use_sideband = 1;
-       if (server_supports("quiet"))
-               quiet_supported = 1;
-       if (server_supports("agent"))
-               agent_supported = 1;
-
-       if (!remote_refs) {
-               fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
-                       "Perhaps you should specify a branch such as 'master'.\n");
-               return 0;
-       }
-
-       /*
-        * Finally, tell the other end!
-        */
-       new_refs = 0;
-       for (ref = remote_refs; ref; ref = ref->next) {
-               if (!ref->peer_ref && !args->send_mirror)
-                       continue;
-
-               /* Check for statuses set by set_ref_status_for_push() */
-               switch (ref->status) {
-               case REF_STATUS_REJECT_NONFASTFORWARD:
-               case REF_STATUS_UPTODATE:
-                       continue;
-               default:
-                       ; /* do nothing */
-               }
-
-               if (ref->deletion && !allow_deleting_refs) {
-                       ref->status = REF_STATUS_REJECT_NODELETE;
-                       continue;
-               }
-
-               if (!ref->deletion)
-                       new_refs++;
-
-               if (args->dry_run) {
-                       ref->status = REF_STATUS_OK;
-               } else {
-                       char *old_hex = sha1_to_hex(ref->old_sha1);
-                       char *new_hex = sha1_to_hex(ref->new_sha1);
-                       int quiet = quiet_supported && (args->quiet || !args->progress);
-
-                       if (!cmds_sent && (status_report || use_sideband ||
-                                          quiet || agent_supported)) {
-                               packet_buf_write(&req_buf,
-                                                "%s %s %s%c%s%s%s%s%s",
-                                                old_hex, new_hex, ref->name, 0,
-                                                status_report ? " report-status" : "",
-                                                use_sideband ? " side-band-64k" : "",
-                                                quiet ? " quiet" : "",
-                                                agent_supported ? " agent=" : "",
-                                                agent_supported ? git_user_agent_sanitized() : ""
-                                               );
-                       }
-                       else
-                               packet_buf_write(&req_buf, "%s %s %s",
-                                                old_hex, new_hex, ref->name);
-                       ref->status = status_report ?
-                               REF_STATUS_EXPECTING_REPORT :
-                               REF_STATUS_OK;
-                       cmds_sent++;
-               }
-       }
-
-       if (args->stateless_rpc) {
-               if (!args->dry_run && cmds_sent) {
-                       packet_buf_flush(&req_buf);
-                       send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
-               }
-       } else {
-               safe_write(out, req_buf.buf, req_buf.len);
-               packet_flush(out);
-       }
-       strbuf_release(&req_buf);
-
-       if (use_sideband && cmds_sent) {
-               memset(&demux, 0, sizeof(demux));
-               demux.proc = sideband_demux;
-               demux.data = fd;
-               demux.out = -1;
-               if (start_async(&demux))
-                       die("send-pack: unable to fork off sideband demultiplexer");
-               in = demux.out;
-       }
-
-       if (new_refs && cmds_sent) {
-               if (pack_objects(out, remote_refs, extra_have, args) < 0) {
-                       for (ref = remote_refs; ref; ref = ref->next)
-                               ref->status = REF_STATUS_NONE;
-                       if (args->stateless_rpc)
-                               close(out);
-                       if (git_connection_is_socket(conn))
-                               shutdown(fd[0], SHUT_WR);
-                       if (use_sideband)
-                               finish_async(&demux);
-                       return -1;
-               }
-       }
-       if (args->stateless_rpc && cmds_sent)
-               packet_flush(out);
-
-       if (status_report && cmds_sent)
-               ret = receive_status(in, remote_refs);
-       else
-               ret = 0;
-       if (args->stateless_rpc)
-               packet_flush(out);
-
-       if (use_sideband && cmds_sent) {
-               if (finish_async(&demux)) {
-                       error("error in sideband demultiplexer");
-                       ret = -1;
-               }
-               close(demux.out);
-       }
-
-       if (ret < 0)
-               return ret;
-
-       if (args->porcelain)
-               return 0;
-
-       for (ref = remote_refs; ref; ref = ref->next) {
-               switch (ref->status) {
-               case REF_STATUS_NONE:
-               case REF_STATUS_UPTODATE:
-               case REF_STATUS_OK:
-                       break;
-               default:
-                       return -1;
-               }
-       }
-       return 0;
-}
-
 int cmd_send_pack(int argc, const char **argv, const char *prefix)
 {
        int i, nr_refspecs = 0;
index b316cf3..8360514 100644 (file)
@@ -306,9 +306,8 @@ parse_done:
 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 4eb016d..8d9b76a 100644 (file)
@@ -28,7 +28,6 @@ static void show_one(const char *refname, const unsigned char *sha1)
 
 static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
 {
-       struct object *obj;
        const char *hex;
        unsigned char peeled[20];
 
@@ -79,25 +78,9 @@ match:
        if (!deref_tags)
                return 0;
 
-       if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
-               if (!is_null_sha1(peeled)) {
-                       hex = find_unique_abbrev(peeled, abbrev);
-                       printf("%s %s^{}\n", hex, refname);
-               }
-       }
-       else {
-               obj = parse_object(sha1);
-               if (!obj)
-                       die("git show-ref: bad ref %s (%s)", refname,
-                           sha1_to_hex(sha1));
-               if (obj->type == OBJ_TAG) {
-                       obj = deref_tag(obj, refname, 0);
-                       if (!obj)
-                               die("git show-ref: bad tag at ref %s (%s)", refname,
-                                   sha1_to_hex(sha1));
-                       hex = find_unique_abbrev(obj->sha1, abbrev);
-                       printf("%s %s^{}\n", hex, refname);
-               }
+       if (!peel_ref(refname, peeled)) {
+               hex = find_unique_abbrev(peeled, abbrev);
+               printf("%s %s^{}\n", hex, refname);
        }
        return 0;
 }
index 9e92828..f481959 100644 (file)
@@ -5,12 +5,11 @@
 
 static const char * const git_symbolic_ref_usage[] = {
        N_("git symbolic-ref [options] name [ref]"),
+       N_("git symbolic-ref -d [-q] name"),
        NULL
 };
 
-static int shorten;
-
-static void check_symref(const char *HEAD, int quiet)
+static int check_symref(const char *HEAD, int quiet, int shorten, int print)
 {
        unsigned char sha1[20];
        int flag;
@@ -22,20 +21,24 @@ static void check_symref(const char *HEAD, int quiet)
                if (!quiet)
                        die("ref %s is not a symbolic ref", HEAD);
                else
-                       exit(1);
+                       return 1;
+       }
+       if (print) {
+               if (shorten)
+                       refname = shorten_unambiguous_ref(refname, 0);
+               puts(refname);
        }
-       if (shorten)
-               refname = shorten_unambiguous_ref(refname, 0);
-       puts(refname);
+       return 0;
 }
 
 int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 {
-       int quiet = 0;
+       int quiet = 0, delete = 0, shorten = 0, ret = 0;
        const char *msg = NULL;
        struct option options[] = {
                OPT__QUIET(&quiet,
                        N_("suppress error message for non-symbolic (detached) refs")),
+               OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
                OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
                OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_END(),
@@ -46,9 +49,19 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
                             git_symbolic_ref_usage, 0);
        if (msg &&!*msg)
                die("Refusing to perform update with empty message");
+
+       if (delete) {
+               if (argc != 1)
+                       usage_with_options(git_symbolic_ref_usage, options);
+               ret = check_symref(argv[0], 1, 0, 0);
+               if (ret)
+                       die("Cannot delete %s, not a symbolic ref", argv[0]);
+               return delete_ref(argv[0], NULL, REF_NODEREF);
+       }
+
        switch (argc) {
        case 1:
-               check_symref(argv[0], quiet);
+               ret = check_symref(argv[0], quiet, shorten, 1);
                break;
        case 2:
                if (!strcmp(argv[0], "HEAD") &&
@@ -59,5 +72,5 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
        default:
                usage_with_options(git_symbolic_ref_usage, options);
        }
-       return 0;
+       return ret;
 }
index 74986bf..ada1dff 100644 (file)
@@ -593,6 +593,7 @@ struct refresh_params {
 static int refresh(struct refresh_params *o, unsigned int flag)
 {
        setup_work_tree();
+       read_cache_preload(NULL);
        *o->has_errors |= refresh_cache(o->flags | flag);
        return 0;
 }
index 28ed657..37e4d00 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 d8cb2e9..55d0f59 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 a58df84..2b192d2 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);
@@ -1149,11 +1150,8 @@ struct config_include_data {
 #define CONFIG_INCLUDE_INIT { 0 }
 extern int git_config_include(const char *name, const char *value, void *data);
 
-#define IDENT_NAME_GIVEN 01
-#define IDENT_MAIL_GIVEN 02
-#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
-extern int user_ident_explicitly_given;
-extern int user_ident_sufficiently_given(void);
+extern int committer_ident_sufficiently_given(void);
+extern int author_ident_sufficiently_given(void);
 
 extern const char *git_commit_encoding;
 extern const char *git_log_output_encoding;
@@ -1183,6 +1181,7 @@ extern int pager_in_use(void);
 extern int pager_use_color;
 extern int term_columns(void);
 extern int decimal_width(int);
+extern int check_pager_config(const char *cmd);
 
 extern const char *editor_program;
 extern const char *askpass_program;
@@ -1265,8 +1264,15 @@ struct startup_info {
 };
 extern struct startup_info *startup_info;
 
-/* builtin/merge.c */
-int checkout_fast_forward(const unsigned char *from, const unsigned char *to);
+/* merge.c */
+struct commit_list;
+int try_merge_command(const char *strategy, size_t xopts_nr,
+               const char **xopts, struct commit_list *common,
+               const char *head_arg, struct commit_list *remotes);
+int checkout_fast_forward(const unsigned char *from,
+                         const unsigned char *to,
+                         int overwrite_ignore);
+
 
 int sane_execvp(const char *file, char *const argv[]);
 
index 213bc98..e8eb0ae 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1347,3 +1347,13 @@ struct commit_list **commit_list_append(struct commit *commit,
        new->next = NULL;
        return &new->next;
 }
+
+void print_commit_list(struct commit_list *list,
+                      const char *format_cur,
+                      const char *format_last)
+{
+       for ( ; list; list = list->next) {
+               const char *format = list->next ? format_cur : format_last;
+               printf(format, sha1_to_hex(list->item->object.sha1));
+       }
+}
index 9f21313..b6ad8f3 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -86,7 +86,7 @@ struct pretty_print_context {
        enum date_mode date_mode;
        unsigned date_mode_explicit:1;
        int need_8bit_cte;
-       int show_notes;
+       char *notes_message;
        struct reflog_walk_info *reflog_info;
        const char *output_encoding;
 };
@@ -99,8 +99,6 @@ extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern char *logmsg_reencode(const struct commit *commit,
                             const char *output_encoding);
-extern char *reencode_commit_message(const struct commit *commit,
-                                    const char **encoding_p);
 extern void get_commit_format(const char *arg, struct rev_info *);
 extern const char *format_subject(struct strbuf *sb, const char *msg,
                                  const char *line_separator);
@@ -222,4 +220,8 @@ struct commit *get_merge_parent(const char *name);
 
 extern int parse_signed_commit(const unsigned char *sha1,
                               struct strbuf *message, struct strbuf *signature);
+extern void print_commit_list(struct commit_list *list,
+                             const char *format_cur,
+                             const char *format_last);
+
 #endif /* COMMIT_H */
index dfe9b30..5428858 100644 (file)
@@ -1,6 +1,13 @@
 #define WIN32_LEAN_AND_MEAN
+#ifdef CYGWIN_V15_WIN32API
 #include "../git-compat-util.h"
 #include "win32.h"
+#else
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include "win32.h"
+#include "../git-compat-util.h"
+#endif
 #include "../cache.h" /* to read configuration */
 
 static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
index 9473aed..b8b7dc2 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;
@@ -345,7 +345,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags)
 
                    for (;;)
                      {
-                       if (c1 == CHAR_CLASS_MAX_LENGTH)
+                       if (c1 > CHAR_CLASS_MAX_LENGTH)
                          /* The name is too long and therefore the pattern
                             is ill-formed.  */
                          return FNM_NOMATCH;
@@ -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 afc892d..b673625 100644 (file)
@@ -256,6 +256,8 @@ int mingw_rmdir(const char *pathname)
 
        while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
                if (!is_file_in_use_error(GetLastError()))
+                       errno = err_win_to_posix(GetLastError());
+               if (errno != EACCES)
                        break;
                if (!is_dir_empty(pathname)) {
                        errno = ENOTEMPTY;
@@ -271,7 +273,7 @@ int mingw_rmdir(const char *pathname)
                Sleep(delay[tries]);
                tries++;
        }
-       while (ret == -1 && is_file_in_use_error(GetLastError()) &&
+       while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
               ask_yes_no_if_possible("Deletion of directory '%s' failed. "
                        "Should I try again?", pathname))
               ret = rmdir(pathname);
@@ -319,6 +321,31 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
        return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
+static BOOL WINAPI ctrl_ignore(DWORD type)
+{
+       return TRUE;
+}
+
+#undef fgetc
+int mingw_fgetc(FILE *stream)
+{
+       int ch;
+       if (!isatty(_fileno(stream)))
+               return fgetc(stream);
+
+       SetConsoleCtrlHandler(ctrl_ignore, TRUE);
+       while (1) {
+               ch = fgetc(stream);
+               if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
+                       break;
+
+               /* Ctrl+C was pressed, simulate SIGINT and retry */
+               mingw_raise(SIGINT);
+       }
+       SetConsoleCtrlHandler(ctrl_ignore, FALSE);
+       return ch;
+}
+
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
@@ -335,6 +362,28 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
        return freopen(filename, otype, stream);
 }
 
+#undef fflush
+int mingw_fflush(FILE *stream)
+{
+       int ret = fflush(stream);
+
+       /*
+        * write() is used behind the scenes of stdio output functions.
+        * Since git code does not check for errors after each stdio write
+        * operation, it can happen that write() is called by a later
+        * stdio function even if an earlier write() call failed. In the
+        * case of a pipe whose readable end was closed, only the first
+        * call to write() reports EPIPE on Windows. Subsequent write()
+        * calls report EINVAL. It is impossible to notice whether this
+        * fflush invocation triggered such a case, therefore, we have to
+        * catch all EINVAL errors whole-sale.
+        */
+       if (ret && errno == EINVAL)
+               errno = EPIPE;
+
+       return ret;
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -1524,7 +1573,7 @@ static HANDLE timer_event;
 static HANDLE timer_thread;
 static int timer_interval;
 static int one_shot;
-static sig_handler_t timer_fn = SIG_DFL;
+static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
 
 /* The timer works like this:
  * The thread, ticktack(), is a trivial routine that most of the time
@@ -1538,10 +1587,7 @@ static sig_handler_t timer_fn = SIG_DFL;
 static unsigned __stdcall ticktack(void *dummy)
 {
        while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
-               if (timer_fn == SIG_DFL)
-                       die("Alarm");
-               if (timer_fn != SIG_IGN)
-                       timer_fn(SIGALRM);
+               mingw_raise(SIGALRM);
                if (one_shot)
                        break;
        }
@@ -1632,12 +1678,49 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out)
 sig_handler_t mingw_signal(int sig, sig_handler_t handler)
 {
        sig_handler_t old = timer_fn;
-       if (sig != SIGALRM)
+
+       switch (sig) {
+       case SIGALRM:
+               timer_fn = handler;
+               break;
+
+       case SIGINT:
+               sigint_fn = handler;
+               break;
+
+       default:
                return signal(sig, handler);
-       timer_fn = handler;
+       }
+
        return old;
 }
 
+#undef raise
+int mingw_raise(int sig)
+{
+       switch (sig) {
+       case SIGALRM:
+               if (timer_fn == SIG_DFL) {
+                       if (isatty(STDERR_FILENO))
+                               fputs("Alarm clock\n", stderr);
+                       exit(128 + SIGALRM);
+               } else if (timer_fn != SIG_IGN)
+                       timer_fn(SIGALRM);
+               return 0;
+
+       case SIGINT:
+               if (sigint_fn == SIG_DFL)
+                       exit(128 + SIGINT);
+               else if (sigint_fn != SIG_IGN)
+                       sigint_fn(SIGINT);
+               return 0;
+
+       default:
+               return raise(sig);
+       }
+}
+
+
 static const char *make_backslash_path(const char *path)
 {
        static char buf[PATH_MAX + 1];
@@ -1699,21 +1782,6 @@ int link(const char *oldpath, const char *newpath)
        return 0;
 }
 
-char *getpass(const char *prompt)
-{
-       struct strbuf buf = STRBUF_INIT;
-
-       fputs(prompt, stderr);
-       for (;;) {
-               char c = _getch();
-               if (c == '\r' || c == '\n')
-                       break;
-               strbuf_addch(&buf, c);
-       }
-       fputs("\n", stderr);
-       return strbuf_detach(&buf, NULL);
-}
-
 pid_t waitpid(pid_t pid, int *status, int options)
 {
        HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
index 61a6521..685cd2c 100644 (file)
@@ -55,8 +55,6 @@ struct passwd {
        char *pw_dir;
 };
 
-extern char *getpass(const char *prompt);
-
 typedef void (__cdecl *sig_handler_t)(int);
 struct sigaction {
        sig_handler_t sa_handler;
@@ -179,12 +177,18 @@ int mingw_open (const char *filename, int oflags, ...);
 ssize_t mingw_write(int fd, const void *buf, size_t count);
 #define write mingw_write
 
+int mingw_fgetc(FILE *stream);
+#define fgetc mingw_fgetc
+
 FILE *mingw_fopen (const char *filename, const char *otype);
 #define fopen mingw_fopen
 
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_fflush(FILE *stream);
+#define fflush mingw_fflush
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 
@@ -287,6 +291,9 @@ static inline unsigned int git_ntohl(unsigned int x)
 sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 #define signal mingw_signal
 
+int mingw_raise(int sig);
+#define raise mingw_raise
+
 /*
  * ANSI emulation wrappers
  */
index d9a17a8..91c4e7f 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 bbb038d..9b5e3d1 100644 (file)
@@ -3,8 +3,22 @@
 #include "sigchain.h"
 #include "strbuf.h"
 
+#if defined(HAVE_DEV_TTY) || defined(WIN32)
+
+static void restore_term(void);
+
+static void restore_term_on_signal(int sig)
+{
+       restore_term();
+       sigchain_pop(sig);
+       raise(sig);
+}
+
 #ifdef HAVE_DEV_TTY
 
+#define INPUT_PATH "/dev/tty"
+#define OUTPUT_PATH "/dev/tty"
+
 static int term_fd = -1;
 static struct termios old_term;
 
@@ -14,58 +28,109 @@ static void restore_term(void)
                return;
 
        tcsetattr(term_fd, TCSAFLUSH, &old_term);
+       close(term_fd);
        term_fd = -1;
 }
 
-static void restore_term_on_signal(int sig)
+static int disable_echo(void)
 {
-       restore_term();
-       sigchain_pop(sig);
-       raise(sig);
+       struct termios t;
+
+       term_fd = open("/dev/tty", O_RDWR);
+       if (tcgetattr(term_fd, &t) < 0)
+               goto error;
+
+       old_term = t;
+       sigchain_push_common(restore_term_on_signal);
+
+       t.c_lflag &= ~ECHO;
+       if (!tcsetattr(term_fd, TCSAFLUSH, &t))
+               return 0;
+
+error:
+       close(term_fd);
+       term_fd = -1;
+       return -1;
+}
+
+#elif defined(WIN32)
+
+#define INPUT_PATH "CONIN$"
+#define OUTPUT_PATH "CONOUT$"
+#define FORCE_TEXT "t"
+
+static HANDLE hconin = INVALID_HANDLE_VALUE;
+static DWORD cmode;
+
+static void restore_term(void)
+{
+       if (hconin == INVALID_HANDLE_VALUE)
+               return;
+
+       SetConsoleMode(hconin, cmode);
+       CloseHandle(hconin);
+       hconin = INVALID_HANDLE_VALUE;
 }
 
+static int disable_echo(void)
+{
+       hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+           FILE_SHARE_READ, NULL, OPEN_EXISTING,
+           FILE_ATTRIBUTE_NORMAL, NULL);
+       if (hconin == INVALID_HANDLE_VALUE)
+               return -1;
+
+       GetConsoleMode(hconin, &cmode);
+       sigchain_push_common(restore_term_on_signal);
+       if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) {
+               CloseHandle(hconin);
+               hconin = INVALID_HANDLE_VALUE;
+               return -1;
+       }
+
+       return 0;
+}
+
+#endif
+
+#ifndef FORCE_TEXT
+#define FORCE_TEXT
+#endif
+
 char *git_terminal_prompt(const char *prompt, int echo)
 {
        static struct strbuf buf = STRBUF_INIT;
        int r;
-       FILE *fh;
+       FILE *input_fh, *output_fh;
 
-       fh = fopen("/dev/tty", "w+");
-       if (!fh)
+       input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT);
+       if (!input_fh)
                return NULL;
 
-       if (!echo) {
-               struct termios t;
-
-               if (tcgetattr(fileno(fh), &t) < 0) {
-                       fclose(fh);
-                       return NULL;
-               }
-
-               old_term = t;
-               term_fd = fileno(fh);
-               sigchain_push_common(restore_term_on_signal);
-
-               t.c_lflag &= ~ECHO;
-               if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
-                       term_fd = -1;
-                       fclose(fh);
-                       return NULL;
-               }
+       output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT);
+       if (!output_fh) {
+               fclose(input_fh);
+               return NULL;
+       }
+
+       if (!echo && disable_echo()) {
+               fclose(input_fh);
+               fclose(output_fh);
+               return NULL;
        }
 
-       fputs(prompt, fh);
-       fflush(fh);
+       fputs(prompt, output_fh);
+       fflush(output_fh);
 
-       r = strbuf_getline(&buf, fh, '\n');
+       r = strbuf_getline(&buf, input_fh, '\n');
        if (!echo) {
-               fseek(fh, SEEK_CUR, 0);
-               putc('\n', fh);
-               fflush(fh);
+               putc('\n', output_fh);
+               fflush(output_fh);
        }
 
        restore_term();
-       fclose(fh);
+       fclose(input_fh);
+       fclose(output_fh);
 
        if (r == EOF)
                return NULL;
index 08e47e2..b569635 100644 (file)
--- a/config.c
+++ b/config.c
@@ -10,8 +10,6 @@
 #include "strbuf.h"
 #include "quote.h"
 
-#define MAXNAME (256)
-
 typedef struct config_file {
        struct config_file *prev;
        FILE *f;
@@ -19,7 +17,7 @@ typedef struct config_file {
        int linenr;
        int eof;
        struct strbuf value;
-       char var[MAXNAME];
+       struct strbuf var;
 } config_file;
 
 static config_file *cf;
@@ -60,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");
@@ -260,7 +258,7 @@ static inline int iskeychar(int c)
        return isalnum(c) || c == '-';
 }
 
-static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
+static int get_value(config_fn_t fn, void *data, struct strbuf *name)
 {
        int c;
        char *value;
@@ -272,11 +270,9 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
                        break;
                if (!iskeychar(c))
                        break;
-               name[len++] = tolower(c);
-               if (len >= MAXNAME)
-                       return -1;
+               strbuf_addch(name, tolower(c));
        }
-       name[len] = 0;
+
        while (c == ' ' || c == '\t')
                c = get_next_char();
 
@@ -288,10 +284,10 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
                if (!value)
                        return -1;
        }
-       return fn(name, value, data);
+       return fn(name->buf, value, data);
 }
 
-static int get_extended_base_var(char *name, int baselen, int c)
+static int get_extended_base_var(struct strbuf *name, int c)
 {
        do {
                if (c == '\n')
@@ -302,7 +298,7 @@ static int get_extended_base_var(char *name, int baselen, int c)
        /* We require the format to be '[base "extension"]' */
        if (c != '"')
                return -1;
-       name[baselen++] = '.';
+       strbuf_addch(name, '.');
 
        for (;;) {
                int c = get_next_char();
@@ -315,37 +311,31 @@ static int get_extended_base_var(char *name, int baselen, int c)
                        if (c == '\n')
                                goto error_incomplete_line;
                }
-               name[baselen++] = c;
-               if (baselen > MAXNAME / 2)
-                       return -1;
+               strbuf_addch(name, c);
        }
 
        /* Final ']' */
        if (get_next_char() != ']')
                return -1;
-       return baselen;
+       return 0;
 error_incomplete_line:
        cf->linenr--;
        return -1;
 }
 
-static int get_base_var(char *name)
+static int get_base_var(struct strbuf *name)
 {
-       int baselen = 0;
-
        for (;;) {
                int c = get_next_char();
                if (cf->eof)
                        return -1;
                if (c == ']')
-                       return baselen;
+                       return 0;
                if (isspace(c))
-                       return get_extended_base_var(name, baselen, c);
+                       return get_extended_base_var(name, c);
                if (!iskeychar(c) && c != '.')
                        return -1;
-               if (baselen > MAXNAME / 2)
-                       return -1;
-               name[baselen++] = tolower(c);
+               strbuf_addch(name, tolower(c));
        }
 }
 
@@ -353,7 +343,7 @@ static int git_parse_file(config_fn_t fn, void *data)
 {
        int comment = 0;
        int baselen = 0;
-       char *var = cf->var;
+       struct strbuf *var = &cf->var;
 
        /* U+FEFF Byte Order Mark in UTF8 */
        static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
@@ -389,17 +379,24 @@ static int git_parse_file(config_fn_t fn, void *data)
                        continue;
                }
                if (c == '[') {
-                       baselen = get_base_var(var);
-                       if (baselen <= 0)
+                       /* Reset prior to determining a new stem */
+                       strbuf_reset(var);
+                       if (get_base_var(var) < 0 || var->len < 1)
                                break;
-                       var[baselen++] = '.';
-                       var[baselen] = 0;
+                       strbuf_addch(var, '.');
+                       baselen = var->len;
                        continue;
                }
                if (!isalpha(c))
                        break;
-               var[baselen] = tolower(c);
-               if (get_value(fn, data, var, baselen+1) < 0)
+               /*
+                * Truncate the var name back to the section header
+                * stem prior to grabbing the suffix part of the name
+                * and the value.
+                */
+               strbuf_setlen(var, baselen);
+               strbuf_addch(var, tolower(c));
+               if (get_value(fn, data, var) < 0)
                        break;
        }
        die("bad config file line %d in %s", cf->linenr, cf->name);
@@ -899,12 +896,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
                top.linenr = 1;
                top.eof = 0;
                strbuf_init(&top.value, 1024);
+               strbuf_init(&top.var, 1024);
                cf = &top;
 
                ret = git_parse_file(fn, data);
 
                /* pop config-file parsing state stack */
                strbuf_release(&top.value);
+               strbuf_release(&top.var);
                cf = top.prev;
 
                fclose(f);
@@ -939,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;
        }
@@ -1280,6 +1279,7 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
 
 out_free_ret_1:
        free(*store_key);
+       *store_key = NULL;
        return -CONFIG_INVALID_KEY;
 }
 
index 69d4838..e8a9bb4 100644 (file)
@@ -18,7 +18,7 @@ datarootdir = @datarootdir@
 template_dir = @datadir@/git-core/templates
 sysconfdir = @sysconfdir@
 
-mandir=@mandir@
+mandir = @mandir@
 
 srcdir = @srcdir@
 VPATH = @srcdir@
index 4c01b0a..a0c8c43 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.67 for git 1.8.0.
+# Generated by GNU Autoconf 2.67 for git 1.8.1.3.
 #
 # Report bugs to <git@vger.kernel.org>.
 #
@@ -552,8 +552,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='git'
 PACKAGE_TARNAME='git'
-PACKAGE_VERSION='1.8.0'
-PACKAGE_STRING='git 1.8.0'
+PACKAGE_VERSION='1.8.1.3'
+PACKAGE_STRING='git 1.8.1.3'
 PACKAGE_BUGREPORT='git@vger.kernel.org'
 PACKAGE_URL=''
 
@@ -1224,7 +1224,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures git 1.8.0 to adapt to many kinds of systems.
+\`configure' configures git 1.8.1.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1285,7 +1285,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of git 1.8.0:";;
+     short | recursive ) echo "Configuration of git 1.8.1.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1424,7 +1424,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-git configure 1.8.0
+git configure 1.8.1.3
 generated by GNU Autoconf 2.67
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1904,7 +1904,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by git $as_me 1.8.0, which was
+It was created by git $as_me 1.8.1.3, which was
 generated by GNU Autoconf 2.67.  Invocation command line was
 
   $ $0 $@
@@ -6431,11 +6431,21 @@ $as_echo "$as_me: Skipping POSIX Threads at user request." >&6;}
 # -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"
-     { $as_echo "$as_me:${as_lineno-$LINENO}: checking Checking for POSIX Threads with '$opt'" >&5
-$as_echo_n "checking Checking for POSIX Threads with '$opt'... " >&6; }
+     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX Threads with '$opt'" >&5
+$as_echo_n "checking for POSIX Threads with '$opt'... " >&6; }
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -6523,8 +6533,8 @@ fi
 else
   old_CFLAGS="$CFLAGS"
   CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking Checking for POSIX Threads with '$PTHREAD_CFLAGS'" >&5
-$as_echo_n "checking Checking for POSIX Threads with '$PTHREAD_CFLAGS'... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX Threads with '$PTHREAD_CFLAGS'" >&5
+$as_echo_n "checking for POSIX Threads with '$PTHREAD_CFLAGS'... " >&6; }
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -7118,7 +7128,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by git $as_me 1.8.0, which was
+This file was extended by git $as_me 1.8.1.3, which was
 generated by GNU Autoconf 2.67.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -7175,7 +7185,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-git config.status 1.8.0
+git config.status 1.8.1.3
 configured by $0, generated by GNU Autoconf 2.67,
   with options \\"\$ac_cs_config\\"
 
index c85888c..41ac9a5 100644 (file)
@@ -1021,10 +1021,20 @@ 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([Checking for POSIX Threads with '$opt'])
+     AC_MSG_CHECKING([for POSIX Threads with '$opt'])
      AC_LINK_IFELSE([PTHREADTEST_SRC],
        [AC_MSG_RESULT([yes])
                NO_PTHREADS=
@@ -1044,7 +1054,7 @@ elif test -z "$PTHREAD_CFLAGS"; then
 else
   old_CFLAGS="$CFLAGS"
   CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
-  AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS'])
+  AC_MSG_CHECKING([for POSIX Threads with '$PTHREAD_CFLAGS'])
   AC_LINK_IFELSE([PTHREADTEST_SRC],
        [AC_MSG_RESULT([yes])
                NO_PTHREADS=
index be800e0..2186b4b 100644 (file)
 #    3) Consider changing your PS1 to also show the current branch,
 #       see git-prompt.sh for details.
 
-if [[ -n ${ZSH_VERSION-} ]]; then
-       autoload -U +X bashcompinit && bashcompinit
-fi
-
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -169,7 +165,6 @@ __git_reassemble_comp_words_by_ref()
 }
 
 if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
-if [[ -z ${ZSH_VERSION:+set} ]]; then
 _get_comp_words_by_ref ()
 {
        local exclude cur_ words_ cword_
@@ -197,32 +192,6 @@ _get_comp_words_by_ref ()
                shift
        done
 }
-else
-_get_comp_words_by_ref ()
-{
-       while [ $# -gt 0 ]; do
-               case "$1" in
-               cur)
-                       cur=${COMP_WORDS[COMP_CWORD]}
-                       ;;
-               prev)
-                       prev=${COMP_WORDS[COMP_CWORD-1]}
-                       ;;
-               words)
-                       words=("${COMP_WORDS[@]}")
-                       ;;
-               cword)
-                       cword=$COMP_CWORD
-                       ;;
-               -n)
-                       # assume COMP_WORDBREAKS is already set sanely
-                       shift
-                       ;;
-               esac
-               shift
-       done
-}
-fi
 fi
 
 # Generates completion reply with compgen, appending a space to possible
@@ -321,7 +290,7 @@ __git_refs ()
                                if [[ "$ref" == "$cur"* ]]; then
                                        echo "$ref"
                                fi
-                       done | uniq -u
+                       done | sort | uniq -u
                fi
                return
        fi
@@ -428,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,$, ,
@@ -562,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;;
@@ -585,7 +563,7 @@ __git_list_porcelain_commands ()
 {
        local i IFS=" "$'\n'
        __git_compute_all_commands
-       for i in "help" $__git_all_commands
+       for i in $__git_all_commands
        do
                case $i in
                *--*)             : helper pattern;;
@@ -989,6 +967,8 @@ _git_clone ()
                        --upload-pack
                        --template=
                        --depth
+                       --single-branch
+                       --branch
                        "
                return
                ;;
@@ -1000,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
@@ -1116,6 +1103,14 @@ _git_fetch ()
        __git_complete_remote_or_refspec
 }
 
+__git_format_patch_options="
+       --stdout --attach --no-attach --thread --thread= --output-directory
+       --numbered --start-number --numbered-files --keep-subject --signoff
+       --signature --no-signature --in-reply-to= --cc= --full-index --binary
+       --not --all --cover-letter --no-prefix --src-prefix= --dst-prefix=
+       --inline --suffix= --ignore-if-in-upstream --subject-prefix=
+"
+
 _git_format_patch ()
 {
        case "$cur" in
@@ -1126,21 +1121,7 @@ _git_format_patch ()
                return
                ;;
        --*)
-               __gitcomp "
-                       --stdout --attach --no-attach --thread --thread=
-                       --output-directory
-                       --numbered --start-number
-                       --numbered-files
-                       --keep-subject
-                       --signoff --signature --no-signature
-                       --in-reply-to= --cc=
-                       --full-index --binary
-                       --not --all
-                       --cover-letter
-                       --no-prefix --src-prefix= --dst-prefix=
-                       --inline --suffix= --ignore-if-in-upstream
-                       --subject-prefix=
-                       "
+               __gitcomp "$__git_format_patch_options"
                return
                ;;
        esac
@@ -1554,6 +1535,12 @@ _git_send_email ()
                __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}"
                return
                ;;
+       --thread=*)
+               __gitcomp "
+                       deep shallow
+                       " "" "${cur##--thread=}"
+               return
+               ;;
        --*)
                __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
                        --compose --confirm= --dry-run --envelope-sender
@@ -1563,11 +1550,12 @@ _git_send_email ()
                        --signed-off-by-cc --smtp-pass --smtp-server
                        --smtp-server-port --smtp-encryption= --smtp-user
                        --subject --suppress-cc= --suppress-from --thread --to
-                       --validate --no-validate"
+                       --validate --no-validate
+                       $__git_format_patch_options"
                return
                ;;
        esac
-       COMPREPLY=()
+       __git_complete_revlist
 }
 
 _git_stage ()
@@ -2429,20 +2417,71 @@ __gitk_main ()
        __git_complete_revlist
 }
 
-__git_func_wrap ()
-{
-       if [[ -n ${ZSH_VERSION-} ]]; then
-               emulate -L bash
-               setopt KSH_TYPESET
+if [[ -n ${ZSH_VERSION-} ]]; then
+       echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2
 
-               # workaround zsh's bug that leaves 'words' as a special
-               # variable in versions < 4.3.12
-               typeset -h words
+       autoload -U +X compinit && compinit
 
-               # workaround zsh's bug that quotes spaces in the COMPREPLY
-               # array if IFS doesn't contain spaces.
-               typeset -h IFS
-       fi
+       __gitcomp ()
+       {
+               emulate -L zsh
+
+               local cur_="${3-$cur}"
+
+               case "$cur_" in
+               --*=)
+                       ;;
+               *)
+                       local c IFS=$' \t\n'
+                       local -a array
+                       for c in ${=1}; do
+                               c="$c${4-}"
+                               case $c in
+                               --*=*|*.) ;;
+                               *) c="$c " ;;
+                               esac
+                               array[$#array+1]="$c"
+                       done
+                       compset -P '*[=:]'
+                       compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
+                       ;;
+               esac
+       }
+
+       __gitcomp_nl ()
+       {
+               emulate -L zsh
+
+               local IFS=$'\n'
+               compset -P '*[=:]'
+               compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
+       }
+
+       __git_zsh_helper ()
+       {
+               emulate -L ksh
+               local cur cword prev
+               cur=${words[CURRENT-1]}
+               prev=${words[CURRENT-2]}
+               let cword=CURRENT-1
+               __${service}_main
+       }
+
+       _git ()
+       {
+               emulate -L zsh
+               local _ret=1
+               __git_zsh_helper
+               let _ret && _default -S '' && _ret=0
+               return _ret
+       }
+
+       compdef _git git gitk
+       return
+fi
+
+__git_func_wrap ()
+{
        local cur words cword prev
        _get_comp_words_by_ref -n =: cur words cword prev
        $1
diff --git a/contrib/completion/git-completion.tcsh b/contrib/completion/git-completion.tcsh
new file mode 100644 (file)
index 0000000..3e3889f
--- /dev/null
@@ -0,0 +1,116 @@
+#!tcsh
+#
+# tcsh completion support for core Git.
+#
+# Copyright (C) 2012 Marc Khouzam <marc.khouzam@gmail.com>
+# Distributed under the GNU General Public License, version 2.0.
+#
+# When sourced, this script will generate a new script that uses
+# the git-completion.bash script provided by core Git.  This new
+# script can be used by tcsh to perform git completion.
+# The current script also issues the necessary tcsh 'complete'
+# commands.
+#
+# 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.
+#       (e.g. ~/.git-completion.tcsh and ~/.git-completion.bash).
+#    2) Add the following line to your .tcshrc/.cshrc:
+#        source ~/.git-completion.tcsh
+#    3) For completion similar to bash, it is recommended to also
+#       add the following line to your .tcshrc/.cshrc:
+#        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
+
+# Check that the user put the script in the right place
+if ( ! -e ${__git_tcsh_completion_original_script} ) then
+       echo "git-completion.tcsh: Cannot find: ${__git_tcsh_completion_original_script}.  Git completion will not work."
+       exit
+endif
+
+cat << EOF > ${__git_tcsh_completion_script}
+#!bash
+#
+# This script is GENERATED and will be overwritten automatically.
+# Do not modify it directly.  Instead, modify git-completion.tcsh
+# and source it again.
+
+source ${__git_tcsh_completion_original_script}
+
+# Set COMP_WORDS in a way that can be handled by the bash script.
+COMP_WORDS=(\$2)
+
+# The cursor is at the end of parameter #1.
+# We must check for a space as the last character which will
+# tell us that the previous word is complete and the cursor
+# is on the next word.
+if [ "\${2: -1}" == " " ]; then
+       # The last character is a space, so our location is at the end
+       # of the command-line array
+       COMP_CWORD=\${#COMP_WORDS[@]}
+else
+       # The last character is not a space, so our location is on the
+       # last word of the command-line array, so we must decrement the
+       # count by 1
+       COMP_CWORD=\$((\${#COMP_WORDS[@]}-1))
+fi
+
+# Call _git() or _gitk() of the bash script, based on the first argument
+_\${1}
+
+IFS=\$'\n'
+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
+       # file completion directly in this script.
+       #
+       # Known issues:
+       #     - Possible completions are shown with their directory prefix.
+       #     - Completions containing shell variables are not handled.
+       #     - Completions with ~ as the first character are not handled.
+
+       # No file completion should be done unless we are completing beyond
+       # the git sub-command.  An improvement on the bash completion :)
+       if [ \${COMP_CWORD} -gt 1 ]; then
+               TO_COMPLETE="\${COMP_WORDS[\${COMP_CWORD}]}"
+
+               # 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.
+                       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
+unset __git_tcsh_completion_original_script
+
+complete git  'p,*,`bash ${__git_tcsh_completion_script} git "${COMMAND_LINE}"`,'
+complete gitk 'p,*,`bash ${__git_tcsh_completion_script} gitk "${COMMAND_LINE}"`,'
diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
new file mode 100644 (file)
index 0000000..4577502
--- /dev/null
@@ -0,0 +1,78 @@
+#compdef git gitk
+
+# zsh completion wrapper for git
+#
+# You need git's bash completion script installed somewhere, by default on the
+# same directory as this script.
+#
+# If your script is on ~/.git-completion.sh instead, you can configure it on
+# your ~/.zshrc:
+#
+#  zstyle ':completion:*:*:git:*' script ~/.git-completion.sh
+#
+# The recommended way to install this script is to copy to
+# '~/.zsh/completion/_git', and then add the following to your ~/.zshrc file:
+#
+#  fpath=(~/.zsh/completion $fpath)
+
+complete ()
+{
+       # do nothing
+       return 0
+}
+
+zstyle -s ":completion:*:*:git:*" script script
+test -z "$script" && script="$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash
+ZSH_VERSION='' . "$script"
+
+__gitcomp ()
+{
+       emulate -L zsh
+
+       local cur_="${3-$cur}"
+
+       case "$cur_" in
+       --*=)
+               ;;
+       *)
+               local c IFS=$' \t\n'
+               local -a array
+               for c in ${=1}; do
+                       c="$c${4-}"
+                       case $c in
+                       --*=*|*.) ;;
+                       *) c="$c " ;;
+                       esac
+                       array+=("$c")
+               done
+               compset -P '*[=:]'
+               compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
+               ;;
+       esac
+}
+
+__gitcomp_nl ()
+{
+       emulate -L zsh
+
+       local IFS=$'\n'
+       compset -P '*[=:]'
+       compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
+}
+
+_git ()
+{
+       local _ret=1
+       () {
+               emulate -L ksh
+               local cur cword prev
+               cur=${words[CURRENT-1]}
+               prev=${words[CURRENT-2]}
+               let cword=CURRENT-1
+               __${service}_main
+       }
+       let _ret && _default -S '' && _ret=0
+       return _ret
+}
+
+_git
index bf20491..9bef053 100644 (file)
 #    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
 #    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-prompt.sh
-#    3) Change your PS1 to also show the current branch:
-#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
-#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+#    3a) Change your PS1 to call __git_ps1 as
+#        command-substitution:
+#        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#        ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+#        the optional argument will be used as format string.
+#    3b) Alternatively, if you are using bash, __git_ps1 can be
+#        used for PROMPT_COMMAND with two parameters, <pre> and
+#        <post>, which are strings you would put in $PS1 before
+#        and after the status string generated by the git-prompt
+#        machinery.  e.g.
+#           PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
+#        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
 # find one, or @{upstream} otherwise.  Once you have set
 # GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
 # setting the bash.showUpstream config variable.
+#
+# If you would like to see more information about the identity of
+# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
+# to one of these values:
+#
+#     contains      relative to newer annotated tag (v1.6.3.2~35)
+#     branch        relative to newer tag or branch (master~4)
+#     describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
+#     default       exactly matching tag
+#
+# If you would like a colored hint about the current dirty state, set
+# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
+# the colored output of "git status -sb".
 
 # __gitdir accepts 0 or 1 arguments (i.e., location)
 # returns location of .git repo
@@ -195,11 +221,43 @@ __git_ps1_show_upstream ()
 
 
 # __git_ps1 accepts 0 or 1 arguments (i.e., format string)
-# returns text to add to bash PS1 prompt (includes branch name)
+# 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 or 3 arguments when called from PROMPT_COMMAND (pc)
+# in that case it _sets_ PS1. The arguments are parts of a PS1 string.
+# 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 ()
 {
+       local pcmode=no
+       local detached=no
+       local ps1pc_start='\u@\h:\w '
+       local ps1pc_end='\$ '
+       local printf_format=' (%s)'
+
+       case "$#" in
+               2|3)    pcmode=yes
+                       ps1pc_start="$1"
+                       ps1pc_end="$2"
+                       printf_format="${3:-$printf_format}"
+               ;;
+               0|1)    printf_format="${1:-$printf_format}"
+               ;;
+               *)      return
+               ;;
+       esac
+
        local g="$(__gitdir)"
-       if [ -n "$g" ]; then
+       if [ -z "$g" ]; then
+               if [ $pcmode = yes ]; then
+                       #In PC mode PS1 always needs to be set
+                       PS1="$ps1pc_start$ps1pc_end"
+               fi
+       else
                local r=""
                local b=""
                if [ -f "$g/rebase-merge/interactive" ]; then
@@ -226,7 +284,7 @@ __git_ps1 ()
                        fi
 
                        b="$(git symbolic-ref HEAD 2>/dev/null)" || {
-
+                               detached=yes
                                b="$(
                                case "${GIT_PS1_DESCRIBE_STYLE-}" in
                                (contains)
@@ -285,6 +343,53 @@ __git_ps1 ()
                fi
 
                local f="$w$i$s$u"
-               printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
+               if [ $pcmode = yes ]; then
+                       local gitstring=
+                       if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
+                               local c_red='\e[31m'
+                               local c_green='\e[32m'
+                               local c_lblue='\e[1;34m'
+                               local c_clear='\e[0m'
+                               local bad_color=$c_red
+                               local ok_color=$c_green
+                               local branch_color="$c_clear"
+                               local flags_color="$c_lblue"
+                               local branchstring="$c${b##refs/heads/}"
+
+                               if [ $detached = no ]; then
+                                       branch_color="$ok_color"
+                               else
+                                       branch_color="$bad_color"
+                               fi
+
+                               # Setting gitstring directly with \[ and \] around colors
+                               # is necessary to prevent wrapping issues!
+                               gitstring="\[$branch_color\]$branchstring\[$c_clear\]"
+
+                               if [ -n "$w$i$s$u$r$p" ]; then
+                                       gitstring="$gitstring "
+                               fi
+                               if [ "$w" = "*" ]; then
+                                       gitstring="$gitstring\[$bad_color\]$w"
+                               fi
+                               if [ -n "$i" ]; then
+                                       gitstring="$gitstring\[$ok_color\]$i"
+                               fi
+                               if [ -n "$s" ]; then
+                                       gitstring="$gitstring\[$flags_color\]$s"
+                               fi
+                               if [ -n "$u" ]; then
+                                       gitstring="$gitstring\[$bad_color\]$u"
+                               fi
+                               gitstring="$gitstring\[$c_clear\]$r$p"
+                       else
+                               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"
+               fi
        fi
 }
index 65c95d9..5ffc506 100644 (file)
@@ -1671,7 +1671,7 @@ Commands:
   "Entry point into git-status mode."
   (interactive "DSelect directory: ")
   (setq dir (git-get-top-dir dir))
-  (if (file-directory-p (concat (file-name-as-directory dir) ".git"))
+  (if (file-exists-p (concat (file-name-as-directory dir) ".git"))
       (let ((buffer (or (and git-reuse-status-buffer (git-find-status-buffer dir))
                         (create-file-buffer (expand-file-name "*git-status*" dir)))))
         (switch-to-buffer buffer)
index 68555d4..094129d 100755 (executable)
@@ -711,6 +711,14 @@ sub fetch_mw_revisions {
        return ($n, @revisions);
 }
 
+sub fe_escape_path {
+    my $path = shift;
+    $path =~ s/\\/\\\\/g;
+    $path =~ s/"/\\"/g;
+    $path =~ s/\n/\\n/g;
+    return '"' . $path . '"';
+}
+
 sub import_file_revision {
        my $commit = shift;
        my %commit = %{$commit};
@@ -738,15 +746,17 @@ sub import_file_revision {
                print STDOUT "from refs/mediawiki/$remotename/master^0\n";
        }
        if ($content ne DELETED_CONTENT) {
-               print STDOUT "M 644 inline $title.mw\n";
+               print STDOUT "M 644 inline " .
+                   fe_escape_path($title . ".mw") . "\n";
                literal_data($content);
                if (%mediafile) {
-                       print STDOUT "M 644 inline $mediafile{title}\n";
+                       print STDOUT "M 644 inline "
+                           . fe_escape_path($mediafile{title}) . "\n";
                        literal_data_raw($mediafile{content});
                }
                print STDOUT "\n\n";
        } else {
-               print STDOUT "D $title.mw\n";
+               print STDOUT "D " . fe_escape_path($title . ".mw") . "\n";
        }
 
        # mediawiki revision number in the git note
index 246d47d..b6405ce 100755 (executable)
@@ -318,4 +318,30 @@ test_expect_success 'git push with \ in format control' '
 '
 
 
+test_expect_success 'fast-import meta-characters in page name (mw -> git)' '
+       wiki_reset &&
+       wiki_editpage \"file\"_\\_foo "expect to be called \"file\"_\\_foo" false &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_21 &&
+       test_path_is_file mw_dir_21/\"file\"_\\_foo.mw &&
+       wiki_getallpage ref_page_21 &&
+       test_diff_directories mw_dir_21 ref_page_21
+'
+
+
+test_expect_success 'fast-import meta-characters in page name (git -> mw) ' '
+       wiki_reset &&
+       git clone mediawiki::'"$WIKI_URL"' mw_dir_22 &&
+       (
+               cd mw_dir_22 &&
+               echo "this file is called \"file\"_\\_foo.mw" >\"file\"_\\_foo &&
+               git add . &&
+               git commit -am "file \"file\"_\\_foo" &&
+               git pull &&
+               git push
+       ) &&
+       wiki_getallpage ref_page_22 &&
+       test_diff_directories mw_dir_22 ref_page_22
+'
+
+
 test_done
diff --git a/contrib/remote-helpers/Makefile b/contrib/remote-helpers/Makefile
new file mode 100644 (file)
index 0000000..9a76575
--- /dev/null
@@ -0,0 +1,13 @@
+TESTS := $(wildcard test*.sh)
+
+export T := $(addprefix $(CURDIR)/,$(TESTS))
+export MAKE := $(MAKE) -e
+export PATH := $(CURDIR):$(PATH)
+
+test:
+       $(MAKE) -C ../../t $@
+
+$(TESTS):
+       $(MAKE) -C ../../t $(CURDIR)/$@
+
+.PHONY: $(TESTS)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
new file mode 100755 (executable)
index 0000000..c700600
--- /dev/null
@@ -0,0 +1,794 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+
+# Inspired by Rocco Rutte's hg-fast-export
+
+# Just copy to your ~/bin, or anywhere in your $PATH.
+# Then you can clone with:
+# git clone hg::/path/to/mercurial/repo/
+
+from mercurial import hg, ui, bookmarks, context, util, encoding
+
+import re
+import sys
+import os
+import json
+import shutil
+import subprocess
+import urllib
+
+#
+# If you want to switch to hg-git compatibility mode:
+# git config --global remote-hg.hg-git-compat true
+#
+# git:
+# Sensible defaults for git.
+# hg bookmarks are exported as git branches, hg branches are prefixed
+# with 'branches/', HEAD is a special case.
+#
+# hg:
+# Emulate hg-git.
+# Only hg bookmarks are exported as git branches.
+# Commits are modified to preserve hg information and allow bidirectionality.
+#
+
+NAME_RE = re.compile('^([^<>]+)')
+AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
+AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$')
+RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
+
+def die(msg, *args):
+    sys.stderr.write('ERROR: %s\n' % (msg % args))
+    sys.exit(1)
+
+def warn(msg, *args):
+    sys.stderr.write('WARNING: %s\n' % (msg % args))
+
+def gitmode(flags):
+    return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644'
+
+def gittz(tz):
+    return '%+03d%02d' % (-tz / 3600, -tz % 3600 / 60)
+
+def hgmode(mode):
+    m = { '0100755': 'x', '0120000': 'l' }
+    return m.get(mode, '')
+
+def get_config(config):
+    cmd = ['git', 'config', '--get', config]
+    process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+    output, _ = process.communicate()
+    return output
+
+class Marks:
+
+    def __init__(self, path):
+        self.path = path
+        self.tips = {}
+        self.marks = {}
+        self.rev_marks = {}
+        self.last_mark = 0
+
+        self.load()
+
+    def load(self):
+        if not os.path.exists(self.path):
+            return
+
+        tmp = json.load(open(self.path))
+
+        self.tips = tmp['tips']
+        self.marks = tmp['marks']
+        self.last_mark = tmp['last-mark']
+
+        for rev, mark in self.marks.iteritems():
+            self.rev_marks[mark] = int(rev)
+
+    def dict(self):
+        return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
+
+    def store(self):
+        json.dump(self.dict(), open(self.path, 'w'))
+
+    def __str__(self):
+        return str(self.dict())
+
+    def from_rev(self, rev):
+        return self.marks[str(rev)]
+
+    def to_rev(self, mark):
+        return self.rev_marks[mark]
+
+    def get_mark(self, rev):
+        self.last_mark += 1
+        self.marks[str(rev)] = self.last_mark
+        return self.last_mark
+
+    def new_mark(self, rev, mark):
+        self.marks[str(rev)] = mark
+        self.rev_marks[mark] = rev
+        self.last_mark = mark
+
+    def is_marked(self, rev):
+        return self.marks.has_key(str(rev))
+
+    def get_tip(self, branch):
+        return self.tips.get(branch, 0)
+
+    def set_tip(self, branch, tip):
+        self.tips[branch] = tip
+
+class Parser:
+
+    def __init__(self, repo):
+        self.repo = repo
+        self.line = self.get_line()
+
+    def get_line(self):
+        return sys.stdin.readline().strip()
+
+    def __getitem__(self, i):
+        return self.line.split()[i]
+
+    def check(self, word):
+        return self.line.startswith(word)
+
+    def each_block(self, separator):
+        while self.line != separator:
+            yield self.line
+            self.line = self.get_line()
+
+    def __iter__(self):
+        return self.each_block('')
+
+    def next(self):
+        self.line = self.get_line()
+        if self.line == 'done':
+            self.line = None
+
+    def get_mark(self):
+        i = self.line.index(':') + 1
+        return int(self.line[i:])
+
+    def get_data(self):
+        if not self.check('data'):
+            return None
+        i = self.line.index(' ') + 1
+        size = int(self.line[i:])
+        return sys.stdin.read(size)
+
+    def get_author(self):
+        global bad_mail
+
+        ex = None
+        m = RAW_AUTHOR_RE.match(self.line)
+        if not m:
+            return None
+        _, name, email, date, tz = m.groups()
+        if name and 'ext:' in name:
+            m = re.match('^(.+?) ext:\((.+)\)$', name)
+            if m:
+                name = m.group(1)
+                ex = urllib.unquote(m.group(2))
+
+        if email != bad_mail:
+            if name:
+                user = '%s <%s>' % (name, email)
+            else:
+                user = '<%s>' % (email)
+        else:
+            user = name
+
+        if ex:
+            user += ex
+
+        tz = int(tz)
+        tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
+        return (user, int(date), -tz)
+
+def export_file(fc):
+    d = fc.data()
+    print "M %s inline %s" % (gitmode(fc.flags()), fc.path())
+    print "data %d" % len(d)
+    print d
+
+def get_filechanges(repo, ctx, parent):
+    modified = set()
+    added = set()
+    removed = set()
+
+    cur = ctx.manifest()
+    prev = repo[parent].manifest().copy()
+
+    for fn in cur:
+        if fn in prev:
+            if (cur.flags(fn) != prev.flags(fn) or cur[fn] != prev[fn]):
+                modified.add(fn)
+            del prev[fn]
+        else:
+            added.add(fn)
+    removed |= set(prev.keys())
+
+    return added | modified, removed
+
+def fixup_user_git(user):
+    name = mail = None
+    user = user.replace('"', '')
+    m = AUTHOR_RE.match(user)
+    if m:
+        name = m.group(1)
+        mail = m.group(2).strip()
+    else:
+        m = NAME_RE.match(user)
+        if m:
+            name = m.group(1).strip()
+    return (name, mail)
+
+def fixup_user_hg(user):
+    def sanitize(name):
+        # stole this from hg-git
+        return re.sub('[<>\n]', '?', name.lstrip('< ').rstrip('> '))
+
+    m = AUTHOR_HG_RE.match(user)
+    if m:
+        name = sanitize(m.group(1))
+        mail = sanitize(m.group(2))
+        ex = m.group(3)
+        if ex:
+            name += ' ext:(' + urllib.quote(ex) + ')'
+    else:
+        name = sanitize(user)
+        if '@' in user:
+            mail = name
+        else:
+            mail = None
+
+    return (name, mail)
+
+def fixup_user(user):
+    global mode, bad_mail
+
+    if mode == 'git':
+        name, mail = fixup_user_git(user)
+    else:
+        name, mail = fixup_user_hg(user)
+
+    if not name:
+        name = bad_name
+    if not mail:
+        mail = bad_mail
+
+    return '%s <%s>' % (name, mail)
+
+def get_repo(url, alias):
+    global dirname, peer
+
+    myui = ui.ui()
+    myui.setconfig('ui', 'interactive', 'off')
+
+    if hg.islocal(url):
+        repo = hg.repository(myui, url)
+    else:
+        local_path = os.path.join(dirname, 'clone')
+        if not os.path.exists(local_path):
+            peer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True)
+            repo = dstpeer.local()
+        else:
+            repo = hg.repository(myui, local_path)
+            peer = hg.peer(myui, {}, url)
+            repo.pull(peer, heads=None, force=True)
+
+    return repo
+
+def rev_to_mark(rev):
+    global marks
+    return marks.from_rev(rev)
+
+def mark_to_rev(mark):
+    global marks
+    return marks.to_rev(mark)
+
+def export_ref(repo, name, kind, head):
+    global prefix, marks, mode
+
+    ename = '%s/%s' % (kind, name)
+    tip = marks.get_tip(ename)
+
+    # mercurial takes too much time checking this
+    if tip and tip == head.rev():
+        # nothing to do
+        return
+    revs = xrange(tip, head.rev() + 1)
+    count = 0
+
+    revs = [rev for rev in revs if not marks.is_marked(rev)]
+
+    for rev in revs:
+
+        c = repo[rev]
+        (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(c.node())
+        rev_branch = extra['branch']
+
+        author = "%s %d %s" % (fixup_user(user), time, gittz(tz))
+        if 'committer' in extra:
+            user, time, tz = extra['committer'].rsplit(' ', 2)
+            committer = "%s %s %s" % (user, time, gittz(int(tz)))
+        else:
+            committer = author
+
+        parents = [p for p in repo.changelog.parentrevs(rev) if p >= 0]
+
+        if len(parents) == 0:
+            modified = c.manifest().keys()
+            removed = []
+        else:
+            modified, removed = get_filechanges(repo, c, parents[0])
+
+        if mode == 'hg':
+            extra_msg = ''
+
+            if rev_branch != 'default':
+                extra_msg += 'branch : %s\n' % rev_branch
+
+            renames = []
+            for f in c.files():
+                if f not in c.manifest():
+                    continue
+                rename = c.filectx(f).renamed()
+                if rename:
+                    renames.append((rename[0], f))
+
+            for e in renames:
+                extra_msg += "rename : %s => %s\n" % e
+
+            for key, value in extra.iteritems():
+                if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
+                    continue
+                else:
+                    extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value))
+
+            desc += '\n'
+            if extra_msg:
+                desc += '\n--HG--\n' + extra_msg
+
+        if len(parents) == 0 and rev:
+            print 'reset %s/%s' % (prefix, ename)
+
+        print "commit %s/%s" % (prefix, ename)
+        print "mark :%d" % (marks.get_mark(rev))
+        print "author %s" % (author)
+        print "committer %s" % (committer)
+        print "data %d" % (len(desc))
+        print desc
+
+        if len(parents) > 0:
+            print "from :%s" % (rev_to_mark(parents[0]))
+            if len(parents) > 1:
+                print "merge :%s" % (rev_to_mark(parents[1]))
+
+        for f in modified:
+            export_file(c.filectx(f))
+        for f in removed:
+            print "D %s" % (f)
+        print
+
+        count += 1
+        if (count % 100 == 0):
+            print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs))
+            print "#############################################################"
+
+    # make sure the ref is updated
+    print "reset %s/%s" % (prefix, ename)
+    print "from :%u" % rev_to_mark(rev)
+    print
+
+    marks.set_tip(ename, rev)
+
+def export_tag(repo, tag):
+    export_ref(repo, tag, 'tags', repo[tag])
+
+def export_bookmark(repo, bmark):
+    head = bmarks[bmark]
+    export_ref(repo, bmark, 'bookmarks', head)
+
+def export_branch(repo, branch):
+    tip = get_branch_tip(repo, branch)
+    head = repo[tip]
+    export_ref(repo, branch, 'branches', head)
+
+def export_head(repo):
+    global g_head
+    export_ref(repo, g_head[0], 'bookmarks', g_head[1])
+
+def do_capabilities(parser):
+    global prefix, dirname
+
+    print "import"
+    print "export"
+    print "refspec refs/heads/branches/*:%s/branches/*" % prefix
+    print "refspec refs/heads/*:%s/bookmarks/*" % prefix
+    print "refspec refs/tags/*:%s/tags/*" % prefix
+
+    path = os.path.join(dirname, 'marks-git')
+
+    if os.path.exists(path):
+        print "*import-marks %s" % path
+    print "*export-marks %s" % path
+
+    print
+
+def get_branch_tip(repo, branch):
+    global branches
+
+    heads = branches.get(branch, None)
+    if not heads:
+        return None
+
+    # verify there's only one head
+    if (len(heads) > 1):
+        warn("Branch '%s' has more than one head, consider merging" % branch)
+        # older versions of mercurial don't have this
+        if hasattr(repo, "branchtip"):
+            return repo.branchtip(branch)
+
+    return heads[0]
+
+def list_head(repo, cur):
+    global g_head, bmarks
+
+    head = bookmarks.readcurrent(repo)
+    if head:
+        node = repo[head]
+    else:
+        # fake bookmark from current branch
+        head = cur
+        node = repo['.']
+        if not node:
+            node = repo['tip']
+        if not node:
+            return
+        if head == 'default':
+            head = 'master'
+        bmarks[head] = node
+
+    print "@refs/heads/%s HEAD" % head
+    g_head = (head, node)
+
+def do_list(parser):
+    global branches, bmarks, mode, track_branches
+
+    repo = parser.repo
+    for bmark, node in bookmarks.listbookmarks(repo).iteritems():
+        bmarks[bmark] = repo[node]
+
+    cur = repo.dirstate.branch()
+
+    list_head(repo, cur)
+
+    if track_branches:
+        for branch in repo.branchmap():
+            heads = repo.branchheads(branch)
+            if len(heads):
+                branches[branch] = heads
+
+        for branch in branches:
+            print "? refs/heads/branches/%s" % branch
+
+    for bmark in bmarks:
+        print "? refs/heads/%s" % bmark
+
+    for tag, node in repo.tagslist():
+        if tag == 'tip':
+            continue
+        print "? refs/tags/%s" % tag
+
+    print
+
+def do_import(parser):
+    repo = parser.repo
+
+    path = os.path.join(dirname, 'marks-git')
+
+    print "feature done"
+    if os.path.exists(path):
+        print "feature import-marks=%s" % path
+    print "feature export-marks=%s" % path
+    sys.stdout.flush()
+
+    tmp = encoding.encoding
+    encoding.encoding = 'utf-8'
+
+    # lets get all the import lines
+    while parser.check('import'):
+        ref = parser[1]
+
+        if (ref == 'HEAD'):
+            export_head(repo)
+        elif ref.startswith('refs/heads/branches/'):
+            branch = ref[len('refs/heads/branches/'):]
+            export_branch(repo, branch)
+        elif ref.startswith('refs/heads/'):
+            bmark = ref[len('refs/heads/'):]
+            export_bookmark(repo, bmark)
+        elif ref.startswith('refs/tags/'):
+            tag = ref[len('refs/tags/'):]
+            export_tag(repo, tag)
+
+        parser.next()
+
+    encoding.encoding = tmp
+
+    print 'done'
+
+def parse_blob(parser):
+    global blob_marks
+
+    parser.next()
+    mark = parser.get_mark()
+    parser.next()
+    data = parser.get_data()
+    blob_marks[mark] = data
+    parser.next()
+    return
+
+def get_merge_files(repo, p1, p2, files):
+    for e in repo[p1].files():
+        if e not in files:
+            if e not in repo[p1].manifest():
+                continue
+            f = { 'ctx' : repo[p1][e] }
+            files[e] = f
+
+def parse_commit(parser):
+    global marks, blob_marks, bmarks, parsed_refs
+    global mode
+
+    from_mark = merge_mark = None
+
+    ref = parser[1]
+    parser.next()
+
+    commit_mark = parser.get_mark()
+    parser.next()
+    author = parser.get_author()
+    parser.next()
+    committer = parser.get_author()
+    parser.next()
+    data = parser.get_data()
+    parser.next()
+    if parser.check('from'):
+        from_mark = parser.get_mark()
+        parser.next()
+    if parser.check('merge'):
+        merge_mark = parser.get_mark()
+        parser.next()
+        if parser.check('merge'):
+            die('octopus merges are not supported yet')
+
+    files = {}
+
+    for line in parser:
+        if parser.check('M'):
+            t, m, mark_ref, path = line.split(' ', 3)
+            mark = int(mark_ref[1:])
+            f = { 'mode' : hgmode(m), 'data' : blob_marks[mark] }
+        elif parser.check('D'):
+            t, path = line.split(' ')
+            f = { 'deleted' : True }
+        else:
+            die('Unknown file command: %s' % line)
+        files[path] = f
+
+    def getfilectx(repo, memctx, f):
+        of = files[f]
+        if 'deleted' in of:
+            raise IOError
+        if 'ctx' in of:
+            return of['ctx']
+        is_exec = of['mode'] == 'x'
+        is_link = of['mode'] == 'l'
+        rename = of.get('rename', None)
+        return context.memfilectx(f, of['data'],
+                is_link, is_exec, rename)
+
+    repo = parser.repo
+
+    user, date, tz = author
+    extra = {}
+
+    if committer != author:
+        extra['committer'] = "%s %u %u" % committer
+
+    if from_mark:
+        p1 = repo.changelog.node(mark_to_rev(from_mark))
+    else:
+        p1 = '\0' * 20
+
+    if merge_mark:
+        p2 = repo.changelog.node(mark_to_rev(merge_mark))
+    else:
+        p2 = '\0' * 20
+
+    #
+    # If files changed from any of the parents, hg wants to know, but in git if
+    # nothing changed from the first parent, nothing changed.
+    #
+    if merge_mark:
+        get_merge_files(repo, p1, p2, files)
+
+    if mode == 'hg':
+        i = data.find('\n--HG--\n')
+        if i >= 0:
+            tmp = data[i + len('\n--HG--\n'):].strip()
+            for k, v in [e.split(' : ') for e in tmp.split('\n')]:
+                if k == 'rename':
+                    old, new = v.split(' => ', 1)
+                    files[new]['rename'] = old
+                elif k == 'branch':
+                    extra[k] = v
+                elif k == 'extra':
+                    ek, ev = v.split(' : ', 1)
+                    extra[ek] = urllib.unquote(ev)
+            data = data[:i]
+
+    ctx = context.memctx(repo, (p1, p2), data,
+            files.keys(), getfilectx,
+            user, (date, tz), extra)
+
+    tmp = encoding.encoding
+    encoding.encoding = 'utf-8'
+
+    node = repo.commitctx(ctx)
+
+    encoding.encoding = tmp
+
+    rev = repo[node].rev()
+
+    parsed_refs[ref] = node
+
+    marks.new_mark(rev, commit_mark)
+
+def parse_reset(parser):
+    ref = parser[1]
+    parser.next()
+    # ugh
+    if parser.check('commit'):
+        parse_commit(parser)
+        return
+    if not parser.check('from'):
+        return
+    from_mark = parser.get_mark()
+    parser.next()
+
+    node = parser.repo.changelog.node(mark_to_rev(from_mark))
+    parsed_refs[ref] = node
+
+def parse_tag(parser):
+    name = parser[1]
+    parser.next()
+    from_mark = parser.get_mark()
+    parser.next()
+    tagger = parser.get_author()
+    parser.next()
+    data = parser.get_data()
+    parser.next()
+
+    # nothing to do
+
+def do_export(parser):
+    global parsed_refs, bmarks, peer
+
+    parser.next()
+
+    for line in parser.each_block('done'):
+        if parser.check('blob'):
+            parse_blob(parser)
+        elif parser.check('commit'):
+            parse_commit(parser)
+        elif parser.check('reset'):
+            parse_reset(parser)
+        elif parser.check('tag'):
+            parse_tag(parser)
+        elif parser.check('feature'):
+            pass
+        else:
+            die('unhandled export command: %s' % line)
+
+    for ref, node in parsed_refs.iteritems():
+        if ref.startswith('refs/heads/branches'):
+            pass
+        elif ref.startswith('refs/heads/'):
+            bmark = ref[len('refs/heads/'):]
+            if bmark in bmarks:
+                old = bmarks[bmark].hex()
+            else:
+                old = ''
+            if not bookmarks.pushbookmark(parser.repo, bmark, old, node):
+                continue
+        elif ref.startswith('refs/tags/'):
+            tag = ref[len('refs/tags/'):]
+            parser.repo.tag([tag], node, None, True, None, {})
+        else:
+            # transport-helper/fast-export bugs
+            continue
+        print "ok %s" % ref
+
+    print
+
+    if peer:
+        parser.repo.push(peer, force=False)
+
+def main(args):
+    global prefix, dirname, branches, bmarks
+    global marks, blob_marks, parsed_refs
+    global peer, mode, bad_mail, bad_name
+    global track_branches
+
+    alias = args[1]
+    url = args[2]
+    peer = None
+
+    hg_git_compat = False
+    track_branches = True
+    try:
+        if get_config('remote-hg.hg-git-compat') == 'true\n':
+            hg_git_compat = True
+            track_branches = False
+        if get_config('remote-hg.track-branches') == 'false\n':
+            track_branches = False
+    except subprocess.CalledProcessError:
+        pass
+
+    if hg_git_compat:
+        mode = 'hg'
+        bad_mail = 'none@none'
+        bad_name = ''
+    else:
+        mode = 'git'
+        bad_mail = 'unknown'
+        bad_name = 'Unknown'
+
+    if alias[4:] == url:
+        is_tmp = True
+        alias = util.sha1(alias).hexdigest()
+    else:
+        is_tmp = False
+
+    gitdir = os.environ['GIT_DIR']
+    dirname = os.path.join(gitdir, 'hg', alias)
+    branches = {}
+    bmarks = {}
+    blob_marks = {}
+    parsed_refs = {}
+
+    repo = get_repo(url, alias)
+    prefix = 'refs/hg/%s' % alias
+
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+
+    marks_path = os.path.join(dirname, 'marks-hg')
+    marks = Marks(marks_path)
+
+    parser = Parser(repo)
+    for line in parser:
+        if parser.check('capabilities'):
+            do_capabilities(parser)
+        elif parser.check('list'):
+            do_list(parser)
+        elif parser.check('import'):
+            do_import(parser)
+        elif parser.check('export'):
+            do_export(parser)
+        else:
+            die('unhandled command: %s' % line)
+        sys.stdout.flush()
+
+    if not is_tmp:
+        marks.store()
+    else:
+        shutil.rmtree(dirname)
+
+sys.exit(main(sys.argv))
diff --git a/contrib/remote-helpers/test-hg-bidi.sh b/contrib/remote-helpers/test-hg-bidi.sh
new file mode 100755 (executable)
index 0000000..1d61982
--- /dev/null
@@ -0,0 +1,243 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+# Base commands from hg-git tests:
+# https://bitbucket.org/durin42/hg-git/src
+#
+
+test_description='Test bidirectionality of remote-hg'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON; then
+       skip_all='skipping remote-hg tests; python not available'
+       test_done
+fi
+
+if ! "$PYTHON_PATH" -c 'import mercurial'; then
+       skip_all='skipping remote-hg tests; mercurial not available'
+       test_done
+fi
+
+# clone to a git repo
+git_clone () {
+       hg -R $1 bookmark -f -r tip master &&
+       git clone -q "hg::$PWD/$1" $2
+}
+
+# clone to an hg repo
+hg_clone () {
+       (
+       hg init $2 &&
+       cd $1 &&
+       git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
+       ) &&
+
+       (cd $2 && hg -q update)
+}
+
+# push an hg repo
+hg_push () {
+       (
+       cd $2
+       old=$(git symbolic-ref --short HEAD)
+       git checkout -q -b tmp &&
+       git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
+       git checkout -q $old &&
+       git branch -q -D tmp 2> /dev/null || true
+       )
+}
+
+hg_log () {
+       hg -R $1 log --graph --debug | grep -v 'tag: *default/'
+}
+
+setup () {
+       (
+       echo "[ui]"
+       echo "username = A U Thor <author@example.com>"
+       echo "[defaults]"
+       echo "backout = -d \"0 0\""
+       echo "commit = -d \"0 0\""
+       echo "debugrawcommit = -d \"0 0\""
+       echo "tag = -d \"0 0\""
+       ) >> "$HOME"/.hgrc &&
+       git config --global remote-hg.hg-git-compat true
+
+       export HGEDITOR=/usr/bin/true
+
+       export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
+       export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+}
+
+setup
+
+test_expect_success 'encoding' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add älphà" &&
+
+       export GIT_AUTHOR_NAME="tést èncödîng" &&
+       echo beta > beta &&
+       git add beta &&
+       git commit -m "add beta" &&
+
+       echo gamma > gamma &&
+       git add gamma &&
+       git commit -m "add gämmâ" &&
+
+       : TODO git config i18n.commitencoding latin-1 &&
+       echo delta > delta &&
+       git add delta &&
+       git commit -m "add déltà"
+       ) &&
+
+       hg_clone gitrepo hgrepo &&
+       git_clone hgrepo gitrepo2 &&
+       hg_clone gitrepo2 hgrepo2 &&
+
+       HGENCODING=utf-8 hg_log hgrepo > expected &&
+       HGENCODING=utf-8 hg_log hgrepo2 > actual &&
+
+       test_cmp expected actual
+'
+
+test_expect_success 'file removal' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add alpha" &&
+       echo beta > beta &&
+       git add beta &&
+       git commit -m "add beta"
+       mkdir foo &&
+       echo blah > foo/bar &&
+       git add foo &&
+       git commit -m "add foo" &&
+       git rm alpha &&
+       git commit -m "remove alpha" &&
+       git rm foo/bar &&
+       git commit -m "remove foo/bar"
+       ) &&
+
+       hg_clone gitrepo hgrepo &&
+       git_clone hgrepo gitrepo2 &&
+       hg_clone gitrepo2 hgrepo2 &&
+
+       hg_log hgrepo > expected &&
+       hg_log hgrepo2 > actual &&
+
+       test_cmp expected actual
+'
+
+test_expect_success 'git tags' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+       git config receive.denyCurrentBranch ignore &&
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add alpha" &&
+       git tag alpha &&
+
+       echo beta > beta &&
+       git add beta &&
+       git commit -m "add beta" &&
+       git tag -a -m "added tag beta" beta
+       ) &&
+
+       hg_clone gitrepo hgrepo &&
+       git_clone hgrepo gitrepo2 &&
+       hg_clone gitrepo2 hgrepo2 &&
+
+       hg_log hgrepo > expected &&
+       hg_log hgrepo2 > actual &&
+
+       test_cmp expected actual
+'
+
+test_expect_success 'hg branch' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -q -m "add alpha" &&
+       git checkout -q -b not-master
+       ) &&
+
+       (
+       hg_clone gitrepo hgrepo &&
+
+       cd hgrepo &&
+       hg -q co master &&
+       hg mv alpha beta &&
+       hg -q commit -m "rename alpha to beta" &&
+       hg branch gamma | grep -v "permanent and global" &&
+       hg -q commit -m "started branch gamma"
+       ) &&
+
+       hg_push hgrepo gitrepo &&
+       hg_clone gitrepo hgrepo2 &&
+
+       : TODO, avoid "master" bookmark &&
+       (cd hgrepo2 && hg checkout gamma) &&
+
+       hg_log hgrepo > expected &&
+       hg_log hgrepo2 > actual &&
+
+       test_cmp expected actual
+'
+
+test_expect_success 'hg tags' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add alpha" &&
+       git checkout -q -b not-master
+       ) &&
+
+       (
+       hg_clone gitrepo hgrepo &&
+
+       cd hgrepo &&
+       hg co master &&
+       hg tag alpha
+       ) &&
+
+       hg_push hgrepo gitrepo &&
+       hg_clone gitrepo hgrepo2 &&
+
+       hg_log hgrepo > expected &&
+       hg_log hgrepo2 > actual &&
+
+       test_cmp expected actual
+'
+
+test_done
diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh
new file mode 100755 (executable)
index 0000000..3e76d9f
--- /dev/null
@@ -0,0 +1,466 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+# Base commands from hg-git tests:
+# https://bitbucket.org/durin42/hg-git/src
+#
+
+test_description='Test remote-hg output compared to hg-git'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON; then
+       skip_all='skipping remote-hg tests; python not available'
+       test_done
+fi
+
+if ! "$PYTHON_PATH" -c 'import mercurial'; then
+       skip_all='skipping remote-hg tests; mercurial not available'
+       test_done
+fi
+
+if ! "$PYTHON_PATH" -c 'import hggit'; then
+       skip_all='skipping remote-hg tests; hg-git not available'
+       test_done
+fi
+
+# clone to a git repo with git
+git_clone_git () {
+       hg -R $1 bookmark -f -r tip master &&
+       git clone -q "hg::$PWD/$1" $2
+}
+
+# clone to an hg repo with git
+hg_clone_git () {
+       (
+       hg init $2 &&
+       cd $1 &&
+       git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
+       ) &&
+
+       (cd $2 && hg -q update)
+}
+
+# clone to a git repo with hg
+git_clone_hg () {
+       (
+       git init -q $2 &&
+       cd $1 &&
+       hg bookmark -f -r tip master &&
+       hg -q push -r master ../$2 || true
+       )
+}
+
+# clone to an hg repo with hg
+hg_clone_hg () {
+       hg -q clone $1 $2
+}
+
+# push an hg repo with git
+hg_push_git () {
+       (
+       cd $2
+       old=$(git symbolic-ref --short HEAD)
+       git checkout -q -b tmp &&
+       git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
+       git checkout -q $old &&
+       git branch -q -D tmp 2> /dev/null || true
+       )
+}
+
+# push an hg git repo with hg
+hg_push_hg () {
+       (
+       cd $1 &&
+       hg -q push ../$2 || true
+       )
+}
+
+hg_log () {
+       hg -R $1 log --graph --debug | grep -v 'tag: *default/'
+}
+
+git_log () {
+       git --git-dir=$1/.git fast-export --branches
+}
+
+setup () {
+       (
+       echo "[ui]"
+       echo "username = A U Thor <author@example.com>"
+       echo "[defaults]"
+       echo "backout = -d \"0 0\""
+       echo "commit = -d \"0 0\""
+       echo "debugrawcommit = -d \"0 0\""
+       echo "tag = -d \"0 0\""
+       echo "[extensions]"
+       echo "hgext.bookmarks ="
+       echo "hggit ="
+       ) >> "$HOME"/.hgrc &&
+       git config --global receive.denycurrentbranch warn
+       git config --global remote-hg.hg-git-compat true
+
+       export HGEDITOR=/usr/bin/true
+
+       export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
+       export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+}
+
+setup
+
+test_expect_success 'merge conflict 1' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       hg init hgrepo1 &&
+       cd hgrepo1 &&
+       echo A > afile &&
+       hg add afile &&
+       hg ci -m "origin" &&
+
+       echo B > afile &&
+       hg ci -m "A->B" &&
+
+       hg up -r0 &&
+       echo C > afile &&
+       hg ci -m "A->C" &&
+
+       hg merge -r1 || true &&
+       echo C > afile &&
+       hg resolve -m afile &&
+       hg ci -m "merge to C"
+       ) &&
+
+       for x in hg git; do
+               git_clone_$x hgrepo1 gitrepo-$x &&
+               hg_clone_$x gitrepo-$x hgrepo2-$x &&
+               hg_log hgrepo2-$x > hg-log-$x &&
+               git_log gitrepo-$x > git-log-$x
+       done &&
+
+       test_cmp hg-log-hg hg-log-git &&
+       test_cmp git-log-hg git-log-git
+'
+
+test_expect_success 'merge conflict 2' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       hg init hgrepo1 &&
+       cd hgrepo1 &&
+       echo A > afile &&
+       hg add afile &&
+       hg ci -m "origin" &&
+
+       echo B > afile &&
+       hg ci -m "A->B" &&
+
+       hg up -r0 &&
+       echo C > afile &&
+       hg ci -m "A->C" &&
+
+       hg merge -r1 || true &&
+       echo B > afile &&
+       hg resolve -m afile &&
+       hg ci -m "merge to B"
+       ) &&
+
+       for x in hg git; do
+               git_clone_$x hgrepo1 gitrepo-$x &&
+               hg_clone_$x gitrepo-$x hgrepo2-$x &&
+               hg_log hgrepo2-$x > hg-log-$x &&
+               git_log gitrepo-$x > git-log-$x
+       done &&
+
+       test_cmp hg-log-hg hg-log-git &&
+       test_cmp git-log-hg git-log-git
+'
+
+test_expect_success 'converged merge' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       hg init hgrepo1 &&
+       cd hgrepo1 &&
+       echo A > afile &&
+       hg add afile &&
+       hg ci -m "origin" &&
+
+       echo B > afile &&
+       hg ci -m "A->B" &&
+
+       echo C > afile &&
+       hg ci -m "B->C" &&
+
+       hg up -r0 &&
+       echo C > afile &&
+       hg ci -m "A->C" &&
+
+       hg merge -r2 || true &&
+       hg ci -m "merge"
+       ) &&
+
+       for x in hg git; do
+               git_clone_$x hgrepo1 gitrepo-$x &&
+               hg_clone_$x gitrepo-$x hgrepo2-$x &&
+               hg_log hgrepo2-$x > hg-log-$x &&
+               git_log gitrepo-$x > git-log-$x
+       done &&
+
+       test_cmp hg-log-hg hg-log-git &&
+       test_cmp git-log-hg git-log-git
+'
+
+test_expect_success 'encoding' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add älphà" &&
+
+       export GIT_AUTHOR_NAME="tést èncödîng" &&
+       echo beta > beta &&
+       git add beta &&
+       git commit -m "add beta" &&
+
+       echo gamma > gamma &&
+       git add gamma &&
+       git commit -m "add gämmâ" &&
+
+       : TODO git config i18n.commitencoding latin-1 &&
+       echo delta > delta &&
+       git add delta &&
+       git commit -m "add déltà"
+       ) &&
+
+       for x in hg git; do
+               hg_clone_$x gitrepo hgrepo-$x &&
+               git_clone_$x hgrepo-$x gitrepo2-$x &&
+
+               HGENCODING=utf-8 hg_log hgrepo-$x > hg-log-$x &&
+               git_log gitrepo2-$x > git-log-$x
+       done &&
+
+       test_cmp hg-log-hg hg-log-git &&
+       test_cmp git-log-hg git-log-git
+'
+
+test_expect_success 'file removal' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add alpha" &&
+       echo beta > beta &&
+       git add beta &&
+       git commit -m "add beta"
+       mkdir foo &&
+       echo blah > foo/bar &&
+       git add foo &&
+       git commit -m "add foo" &&
+       git rm alpha &&
+       git commit -m "remove alpha" &&
+       git rm foo/bar &&
+       git commit -m "remove foo/bar"
+       ) &&
+
+       for x in hg git; do
+               (
+               hg_clone_$x gitrepo hgrepo-$x &&
+               cd hgrepo-$x &&
+               hg_log . &&
+               hg manifest -r 3 &&
+               hg manifest
+               ) > output-$x &&
+
+               git_clone_$x hgrepo-$x gitrepo2-$x &&
+               git_log gitrepo2-$x > log-$x
+       done &&
+
+       test_cmp output-hg output-git &&
+       test_cmp log-hg log-git
+'
+
+test_expect_success 'git tags' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       (
+       git init -q gitrepo &&
+       cd gitrepo &&
+       git config receive.denyCurrentBranch ignore &&
+       echo alpha > alpha &&
+       git add alpha &&
+       git commit -m "add alpha" &&
+       git tag alpha &&
+
+       echo beta > beta &&
+       git add beta &&
+       git commit -m "add beta" &&
+       git tag -a -m "added tag beta" beta
+       ) &&
+
+       for x in hg git; do
+               hg_clone_$x gitrepo hgrepo-$x &&
+               hg_log hgrepo-$x > log-$x
+       done &&
+
+       test_cmp log-hg log-git
+'
+
+test_expect_success 'hg author' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       for x in hg git; do
+               (
+               git init -q gitrepo-$x &&
+               cd gitrepo-$x &&
+
+               echo alpha > alpha &&
+               git add alpha &&
+               git commit -m "add alpha" &&
+               git checkout -q -b not-master
+               ) &&
+
+               (
+               hg_clone_$x gitrepo-$x hgrepo-$x &&
+               cd hgrepo-$x &&
+
+               hg co master &&
+               echo beta > beta &&
+               hg add beta &&
+               hg commit -u "test" -m "add beta" &&
+
+               echo gamma >> beta &&
+               hg commit -u "test <test@example.com> (comment)" -m "modify beta" &&
+
+               echo gamma > gamma &&
+               hg add gamma &&
+               hg commit -u "<test@example.com>" -m "add gamma" &&
+
+               echo delta > delta &&
+               hg add delta &&
+               hg commit -u "name<test@example.com>" -m "add delta" &&
+
+               echo epsilon > epsilon &&
+               hg add epsilon &&
+               hg commit -u "name <test@example.com" -m "add epsilon" &&
+
+               echo zeta > zeta &&
+               hg add zeta &&
+               hg commit -u " test " -m "add zeta" &&
+
+               echo eta > eta &&
+               hg add eta &&
+               hg commit -u "test < test@example.com >" -m "add eta" &&
+
+               echo theta > theta &&
+               hg add theta &&
+               hg commit -u "test >test@example.com>" -m "add theta" &&
+
+               echo iota > iota &&
+               hg add iota &&
+               hg commit -u "test <test <at> example <dot> com>" -m "add iota"
+               ) &&
+
+               hg_push_$x hgrepo-$x gitrepo-$x &&
+               hg_clone_$x gitrepo-$x hgrepo2-$x &&
+
+               hg_log hgrepo2-$x > hg-log-$x &&
+               git_log gitrepo-$x > git-log-$x
+       done &&
+
+       test_cmp git-log-hg git-log-git &&
+
+       test_cmp hg-log-hg hg-log-git &&
+       test_cmp git-log-hg git-log-git
+'
+
+test_expect_success 'hg branch' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       for x in hg git; do
+               (
+               git init -q gitrepo-$x &&
+               cd gitrepo-$x &&
+
+               echo alpha > alpha &&
+               git add alpha &&
+               git commit -q -m "add alpha" &&
+               git checkout -q -b not-master
+               ) &&
+
+               (
+               hg_clone_$x gitrepo-$x hgrepo-$x &&
+
+               cd hgrepo-$x &&
+               hg -q co master &&
+               hg mv alpha beta &&
+               hg -q commit -m "rename alpha to beta" &&
+               hg branch gamma | grep -v "permanent and global" &&
+               hg -q commit -m "started branch gamma"
+               ) &&
+
+               hg_push_$x hgrepo-$x gitrepo-$x &&
+               hg_clone_$x gitrepo-$x hgrepo2-$x &&
+
+               hg_log hgrepo2-$x > hg-log-$x &&
+               git_log gitrepo-$x > git-log-$x
+       done &&
+
+       test_cmp hg-log-hg hg-log-git &&
+       test_cmp git-log-hg git-log-git
+'
+
+test_expect_success 'hg tags' '
+       mkdir -p tmp && cd tmp &&
+       test_when_finished "cd .. && rm -rf tmp" &&
+
+       for x in hg git; do
+               (
+               git init -q gitrepo-$x &&
+               cd gitrepo-$x &&
+
+               echo alpha > alpha &&
+               git add alpha &&
+               git commit -m "add alpha" &&
+               git checkout -q -b not-master
+               ) &&
+
+               (
+               hg_clone_$x gitrepo-$x hgrepo-$x &&
+
+               cd hgrepo-$x &&
+               hg co master &&
+               hg tag alpha
+               ) &&
+
+               hg_push_$x hgrepo-$x gitrepo-$x &&
+               hg_clone_$x gitrepo-$x hgrepo2-$x &&
+
+               (
+               git --git-dir=gitrepo-$x/.git tag -l &&
+               hg_log hgrepo2-$x &&
+               cat hgrepo2-$x/.hgtags
+               ) > output-$x
+       done &&
+
+       test_cmp output-hg output-git
+'
+
+test_done
diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh
new file mode 100755 (executable)
index 0000000..5f81dfa
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+# Base commands from hg-git tests:
+# https://bitbucket.org/durin42/hg-git/src
+#
+
+test_description='Test remote-hg'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON; then
+       skip_all='skipping remote-hg tests; python not available'
+       test_done
+fi
+
+if ! "$PYTHON_PATH" -c 'import mercurial'; then
+       skip_all='skipping remote-hg tests; mercurial not available'
+       test_done
+fi
+
+check () {
+       (cd $1 &&
+       git log --format='%s' -1 &&
+       git symbolic-ref HEAD) > actual &&
+       (echo $2 &&
+       echo "refs/heads/$3") > expected &&
+       test_cmp expected actual
+}
+
+setup () {
+       (
+       echo "[ui]"
+       echo "username = H G Wells <wells@example.com>"
+       ) >> "$HOME"/.hgrc
+}
+
+setup
+
+test_expect_success 'cloning' '
+  test_when_finished "rm -rf gitrepo*" &&
+
+  (
+  hg init hgrepo &&
+  cd hgrepo &&
+  echo zero > content &&
+  hg add content &&
+  hg commit -m zero
+  ) &&
+
+  git clone "hg::$PWD/hgrepo" gitrepo &&
+  check gitrepo zero master
+'
+
+test_expect_success 'cloning with branches' '
+  test_when_finished "rm -rf gitrepo*" &&
+
+  (
+  cd hgrepo &&
+  hg branch next &&
+  echo next > content &&
+  hg commit -m next
+  ) &&
+
+  git clone "hg::$PWD/hgrepo" gitrepo &&
+  check gitrepo next next &&
+
+  (cd hgrepo && hg checkout default) &&
+
+  git clone "hg::$PWD/hgrepo" gitrepo2 &&
+  check gitrepo2 zero master
+'
+
+test_expect_success 'cloning with bookmarks' '
+  test_when_finished "rm -rf gitrepo*" &&
+
+  (
+  cd hgrepo &&
+  hg bookmark feature-a &&
+  echo feature-a > content &&
+  hg commit -m feature-a
+  ) &&
+
+  git clone "hg::$PWD/hgrepo" gitrepo &&
+  check gitrepo feature-a feature-a
+'
+
+test_expect_success 'cloning with detached head' '
+  test_when_finished "rm -rf gitrepo*" &&
+
+  (
+  cd hgrepo &&
+  hg update -r 0
+  ) &&
+
+  git clone "hg::$PWD/hgrepo" gitrepo &&
+  check gitrepo zero master
+'
+
+test_expect_success 'update bookmark' '
+  test_when_finished "rm -rf gitrepo*" &&
+
+  (
+  cd hgrepo &&
+  hg bookmark devel
+  ) &&
+
+  (
+  git clone "hg::$PWD/hgrepo" gitrepo &&
+  cd gitrepo &&
+  git checkout devel &&
+  echo devel > content &&
+  git commit -a -m devel &&
+  git push
+  ) &&
+
+  hg -R hgrepo bookmarks | grep "devel\s\+3:"
+'
+
+test_done
index 4b852e2..9513f5e 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 7e77c9d..91360a3 100644 (file)
@@ -1,4 +1,5 @@
 *~
+git-subtree
 git-subtree.xml
 git-subtree.1
 mainline
index 0c44fda..c5bce41 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 35db24f..f363505 100644 (file)
@@ -10,7 +10,8 @@ int main(int argc, char **argv)
 {
        if (svndump_init(NULL))
                return 1;
-       svndump_read((argc > 1) ? argv[1] : NULL);
+       svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
+                       "refs/notes/svn/revs");
        svndump_deinit();
        svndump_reset();
        return 0;
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
new file mode 100755 (executable)
index 0000000..1cfac4a
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+"""
+Simulates svnrdump by replaying an existing dump from a file, taking care
+of the specified revision range.
+To simulate incremental imports the environment variable SVNRMAX can be set
+to the highest revision that should be available.
+"""
+import sys, os
+
+
+def getrevlimit():
+        var = 'SVNRMAX'
+        if os.environ.has_key(var):
+                return os.environ[var]
+        return None
+
+def writedump(url, lower, upper):
+        if url.startswith('sim://'):
+                filename = url[6:]
+                if filename[-1] == '/': filename = filename[:-1] #remove terminating slash
+        else:
+                raise ValueError('sim:// url required')
+        f = open(filename, 'r');
+        state = 'header'
+        wroterev = False
+        while(True):
+                l = f.readline()
+                if l == '': break
+                if state == 'header' and l.startswith('Revision-number: '):
+                        state = 'prefix'
+                if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
+                        state = 'selection'
+                if not upper == 'HEAD' and state == 'selection' and l == 'Revision-number: %s\n' % upper:
+                        break;
+
+                if state == 'header' or state == 'selection':
+                        if state == 'selection': wroterev = True
+                        sys.stdout.write(l)
+        return wroterev
+
+if __name__ == "__main__":
+        if not (len(sys.argv) in (3, 4, 5)):
+                print "usage: %s dump URL -rLOWER:UPPER"
+                sys.exit(1)
+        if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.')
+        url = sys.argv[2]
+        r = ('0', 'HEAD')
+        if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
+                r = sys.argv[3][2:].lstrip().split(':')
+        if not getrevlimit() is None: r[1] = getrevlimit()
+        if writedump(url, r[0], r[1]): ret = 0
+        else: ret = 1
+        sys.exit(ret)
index fca1e17..8f16d06 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/diff.c b/diff.c
index 35d3f07..732d4c2 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -15,6 +15,7 @@
 #include "sigchain.h"
 #include "submodule.h"
 #include "ll-merge.h"
+#include "string-list.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -26,6 +27,7 @@ static int diff_detect_rename_default;
 static int diff_rename_limit_default = 400;
 static int diff_suppress_blank_empty;
 static int diff_use_color_default = -1;
+static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
 int diff_auto_refresh_index = 1;
@@ -68,26 +70,30 @@ static int parse_diff_color_slot(const char *var, int ofs)
        return -1;
 }
 
-static int parse_dirstat_params(struct diff_options *options, const char *params,
+static int parse_dirstat_params(struct diff_options *options, const char *params_string,
                                struct strbuf *errmsg)
 {
-       const char *p = params;
-       int p_len, ret = 0;
+       char *params_copy = xstrdup(params_string);
+       struct string_list params = STRING_LIST_INIT_NODUP;
+       int ret = 0;
+       int i;
 
-       while (*p) {
-               p_len = strchrnul(p, ',') - p;
-               if (!memcmp(p, "changes", p_len)) {
+       if (*params_copy)
+               string_list_split_in_place(&params, params_copy, ',', -1);
+       for (i = 0; i < params.nr; i++) {
+               const char *p = params.items[i].string;
+               if (!strcmp(p, "changes")) {
                        DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
                        DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
-               } else if (!memcmp(p, "lines", p_len)) {
+               } else if (!strcmp(p, "lines")) {
                        DIFF_OPT_SET(options, DIRSTAT_BY_LINE);
                        DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
-               } else if (!memcmp(p, "files", p_len)) {
+               } else if (!strcmp(p, "files")) {
                        DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
                        DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
-               } else if (!memcmp(p, "noncumulative", p_len)) {
+               } else if (!strcmp(p, "noncumulative")) {
                        DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
-               } else if (!memcmp(p, "cumulative", p_len)) {
+               } else if (!strcmp(p, "cumulative")) {
                        DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
                } else if (isdigit(*p)) {
                        char *end;
@@ -99,27 +105,35 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
                                while (isdigit(*++end))
                                        ; /* nothing */
                        }
-                       if (end - p == p_len)
+                       if (!*end)
                                options->dirstat_permille = permille;
                        else {
-                               strbuf_addf(errmsg, _("  Failed to parse dirstat cut-off percentage '%.*s'\n"),
-                                           p_len, p);
+                               strbuf_addf(errmsg, _("  Failed to parse dirstat cut-off percentage '%s'\n"),
+                                           p);
                                ret++;
                        }
                } else {
-                       strbuf_addf(errmsg, _("  Unknown dirstat parameter '%.*s'\n"),
-                                   p_len, p);
+                       strbuf_addf(errmsg, _("  Unknown dirstat parameter '%s'\n"), p);
                        ret++;
                }
 
-               p += p_len;
-
-               if (*p)
-                       p++; /* more parameters, swallow separator */
        }
+       string_list_clear(&params, 0);
+       free(params_copy);
        return ret;
 }
 
+static int parse_submodule_params(struct diff_options *options, const char *value)
+{
+       if (!strcmp(value, "log"))
+               DIFF_OPT_SET(options, SUBMODULE_LOG);
+       else if (!strcmp(value, "short"))
+               DIFF_OPT_CLR(options, SUBMODULE_LOG);
+       else
+               return -1;
+       return 0;
+}
+
 static int git_config_rename(const char *var, const char *value)
 {
        if (!value)
@@ -141,6 +155,12 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_use_color_default = git_config_colorbool(var, value);
                return 0;
        }
+       if (!strcmp(var, "diff.context")) {
+               diff_context_default = git_config_int(var, value);
+               if (diff_context_default < 0)
+                       return -1;
+               return 0;
+       }
        if (!strcmp(var, "diff.renames")) {
                diff_detect_rename_default = git_config_rename(var, value);
                return 0;
@@ -169,6 +189,13 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "diff.ignoresubmodules"))
                handle_ignore_submodules_arg(&default_diff_options, value);
 
+       if (!strcmp(var, "diff.submodule")) {
+               if (parse_submodule_params(&default_diff_options, value))
+                       warning(_("Unknown value for 'diff.submodule' config variable: '%s'"),
+                               value);
+               return 0;
+       }
+
        if (git_color_config(var, value, cb) < 0)
                return -1;
 
@@ -1300,6 +1327,7 @@ struct diffstat_t {
                unsigned is_unmerged:1;
                unsigned is_binary:1;
                unsigned is_renamed:1;
+               unsigned is_interesting:1;
                uintmax_t added, deleted;
        } **files;
 };
@@ -1469,8 +1497,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
        for (i = 0; (i < count) && (i < data->nr); i++) {
                struct diffstat_file *file = data->files[i];
                uintmax_t change = file->added + file->deleted;
-               if (!data->files[i]->is_renamed &&
-                        (change == 0)) {
+
+               if (!file->is_interesting && (change == 0)) {
                        count++; /* not shown == room for one more */
                        continue;
                }
@@ -1497,7 +1525,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                if (max_change < change)
                        max_change = change;
        }
-       count = i; /* min(count, data->nr) */
+       count = i; /* where we can stop scanning in data->files[] */
 
        /*
         * We have width = stat_width or term_columns() columns total.
@@ -1585,16 +1613,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
         */
        for (i = 0; i < count; i++) {
                const char *prefix = "";
-               char *name = data->files[i]->print_name;
-               uintmax_t added = data->files[i]->added;
-               uintmax_t deleted = data->files[i]->deleted;
+               struct diffstat_file *file = data->files[i];
+               char *name = file->print_name;
+               uintmax_t added = file->added;
+               uintmax_t deleted = file->deleted;
                int name_len;
 
-               if (!data->files[i]->is_renamed &&
-                        (added + deleted == 0)) {
-                       total_files--;
+               if (!file->is_interesting && (added + deleted == 0))
                        continue;
-               }
+
                /*
                 * "scale" the filename
                 */
@@ -1610,7 +1637,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                                name = slash;
                }
 
-               if (data->files[i]->is_binary) {
+               if (file->is_binary) {
                        fprintf(options->file, "%s", line_prefix);
                        show_name(options->file, prefix, name, len);
                        fprintf(options->file, " %*s", number_width, "Bin");
@@ -1627,7 +1654,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                        fprintf(options->file, "\n");
                        continue;
                }
-               else if (data->files[i]->is_unmerged) {
+               else if (file->is_unmerged) {
                        fprintf(options->file, "%s", line_prefix);
                        show_name(options->file, prefix, name, len);
                        fprintf(options->file, " Unmerged\n");
@@ -1639,8 +1666,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                 */
                add = added;
                del = deleted;
-               adds += add;
-               dels += del;
 
                if (graph_width <= max_change) {
                        int total = add + del;
@@ -1666,16 +1691,24 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                show_graph(options->file, '-', del, del_c, reset);
                fprintf(options->file, "\n");
        }
-       for (i = count; i < data->nr; i++) {
-               uintmax_t added = data->files[i]->added;
-               uintmax_t deleted = data->files[i]->deleted;
-               if (!data->files[i]->is_renamed &&
-                        (added + deleted == 0)) {
+
+       for (i = 0; i < data->nr; i++) {
+               struct diffstat_file *file = data->files[i];
+               uintmax_t added = file->added;
+               uintmax_t deleted = file->deleted;
+
+               if (file->is_unmerged ||
+                   (!file->is_interesting && (added + deleted == 0))) {
                        total_files--;
                        continue;
                }
-               adds += added;
-               dels += deleted;
+
+               if (!file->is_binary) {
+                       adds += added;
+                       dels += deleted;
+               }
+               if (i < count)
+                       continue;
                if (!extra_shown)
                        fprintf(options->file, "%s ...\n", line_prefix);
                extra_shown = 1;
@@ -1695,9 +1728,8 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
                int added = data->files[i]->added;
                int deleted= data->files[i]->deleted;
 
-               if (data->files[i]->is_unmerged)
-                       continue;
-               if (!data->files[i]->is_renamed && (added + deleted == 0)) {
+               if (data->files[i]->is_unmerged ||
+                   (!data->files[i]->is_interesting && (added + deleted == 0))) {
                        total_files--;
                } else if (!data->files[i]->is_binary) { /* don't count bytes */
                        adds += added;
@@ -2213,7 +2245,7 @@ static void builtin_diff(const char *name_a,
        mmfile_t mf1, mf2;
        const char *lbl[2];
        char *a_one, *b_two;
-       const char *set = diff_get_color_opt(o, DIFF_METAINFO);
+       const char *meta = diff_get_color_opt(o, DIFF_METAINFO);
        const char *reset = diff_get_color_opt(o, DIFF_RESET);
        const char *a_prefix, *b_prefix;
        struct userdiff_driver *textconv_one = NULL;
@@ -2234,7 +2266,7 @@ static void builtin_diff(const char *name_a,
                const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
                show_submodule_summary(o->file, one ? one->path : two->path,
                                one->sha1, two->sha1, two->dirty_submodule,
-                               del, add, reset);
+                               meta, del, add, reset);
                return;
        }
 
@@ -2260,24 +2292,24 @@ static void builtin_diff(const char *name_a,
        b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
        lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
        lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
-       strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, set, a_one, b_two, reset);
+       strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, meta, a_one, b_two, reset);
        if (lbl[0][0] == '/') {
                /* /dev/null */
-               strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, set, two->mode, reset);
+               strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, meta, two->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
                must_show_header = 1;
        }
        else if (lbl[1][0] == '/') {
-               strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, set, one->mode, reset);
+               strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, meta, one->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
                must_show_header = 1;
        }
        else {
                if (one->mode != two->mode) {
-                       strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, set, one->mode, reset);
-                       strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, set, two->mode, reset);
+                       strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, meta, one->mode, reset);
+                       strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, meta, two->mode, reset);
                        must_show_header = 1;
                }
                if (xfrm_msg)
@@ -2397,13 +2429,20 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                             struct diff_filespec *two,
                             struct diffstat_t *diffstat,
                             struct diff_options *o,
-                            int complete_rewrite)
+                            struct diff_filepair *p)
 {
        mmfile_t mf1, mf2;
        struct diffstat_file *data;
        int same_contents;
+       int complete_rewrite = 0;
+
+       if (!DIFF_PAIR_UNMERGED(p)) {
+               if (p->status == DIFF_STATUS_MODIFIED && p->score)
+                       complete_rewrite = 1;
+       }
 
        data = diffstat_add(diffstat, name_a, name_b);
+       data->is_interesting = p->status != DIFF_STATUS_UNKNOWN;
 
        if (!one || !two) {
                data->is_unmerged = 1;
@@ -3114,11 +3153,10 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
 {
        const char *name;
        const char *other;
-       int complete_rewrite = 0;
 
        if (DIFF_PAIR_UNMERGED(p)) {
                /* unmerged */
-               builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0);
+               builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p);
                return;
        }
 
@@ -3131,9 +3169,7 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
        diff_fill_sha1_info(p->one);
        diff_fill_sha1_info(p->two);
 
-       if (p->status == DIFF_STATUS_MODIFIED && p->score)
-               complete_rewrite = 1;
-       builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite);
+       builtin_diffstat(name, other, p->one, p->two, diffstat, o, p);
 }
 
 static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
@@ -3170,7 +3206,7 @@ void diff_setup(struct diff_options *options)
        options->break_opt = -1;
        options->rename_limit = -1;
        options->dirstat_permille = diff_dirstat_permille_default;
-       options->context = 3;
+       options->context = diff_context_default;
        DIFF_OPT_SET(options, RENAME_EMPTY);
 
        options->change = diff_change;
@@ -3466,6 +3502,14 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params)
        return 1;
 }
 
+static int parse_submodule_opt(struct diff_options *options, const char *value)
+{
+       if (parse_submodule_params(options, value))
+               die(_("Failed to parse --submodule option parameter: '%s'"),
+                       value);
+       return 1;
+}
+
 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 {
        const char *arg = av[0];
@@ -3646,10 +3690,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                handle_ignore_submodules_arg(options, arg + 20);
        } else if (!strcmp(arg, "--submodule"))
                DIFF_OPT_SET(options, SUBMODULE_LOG);
-       else if (!prefixcmp(arg, "--submodule=")) {
-               if (!strcmp(arg + 12, "log"))
-                       DIFF_OPT_SET(options, SUBMODULE_LOG);
-       }
+       else if (!prefixcmp(arg, "--submodule="))
+               return parse_submodule_opt(options, arg + 12);
 
        /* misc options */
        else if (!strcmp(arg, "-z"))
@@ -4871,3 +4913,19 @@ size_t fill_textconv(struct userdiff_driver *driver,
 
        return size;
 }
+
+void setup_diff_pager(struct diff_options *opt)
+{
+       /*
+        * If the user asked for our exit code, then either they want --quiet
+        * or --exit-code. We should definitely not bother with a pager in the
+        * former case, as we will generate no output. Since we still properly
+        * report our exit code even when a pager is run, we _could_ run a
+        * pager with --exit-code. But since we have not done so historically,
+        * and because it is easy to find people oneline advising "git diff
+        * --exit-code" in hooks and other scripts, we do not do so.
+        */
+       if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+           check_pager_config("diff") != 0)
+               setup_pager();
+}
diff --git a/diff.h b/diff.h
index a658f85..a47bae4 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -335,5 +335,6 @@ extern int parse_rename_score(const char **cp_p);
 
 extern int print_stat_summary(FILE *fp, int files,
                              int insertions, int deletions);
+extern void setup_diff_pager(struct diff_options *);
 
 #endif /* DIFF_H */
index ed23eb4..b097fa7 100644 (file)
@@ -104,10 +104,10 @@ static int diff_grep(struct diff_filepair *p, struct diff_options *o,
                if (!mf2.ptr)
                        return 0; /* ignore unmerged */
                /* created "two" -- does it have what we are looking for? */
-               hit = !regexec(regexp, p->two->data, 1, &regmatch, 0);
+               hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 0);
        } else if (!mf2.ptr) {
                /* removed "one" -- did it have what we are looking for? */
-               hit = !regexec(regexp, p->one->data, 1, &regmatch, 0);
+               hit = !regexec(regexp, mf1.ptr, 1, &regmatch, 0);
        } else {
                /*
                 * We have both sides; need to run textual diff and see if
@@ -157,19 +157,15 @@ static void diffcore_pickaxe_grep(struct diff_options *o)
        return;
 }
 
-static unsigned int contains(struct diff_filespec *one, struct diff_options *o,
+static unsigned int contains(mmfile_t *mf, struct diff_options *o,
                             regex_t *regexp, kwset_t kws)
 {
        unsigned int cnt;
        unsigned long sz;
        const char *data;
-       if (!o->pickaxe[0])
-               return 0;
-       if (diff_populate_filespec(one, 0))
-               return 0;
 
-       sz = one->size;
-       data = one->data;
+       sz = mf->size;
+       data = mf->ptr;
        cnt = 0;
 
        if (regexp) {
@@ -199,26 +195,53 @@ static unsigned int contains(struct diff_filespec *one, struct diff_options *o,
                        cnt++;
                }
        }
-       diff_free_filespec_data(one);
        return cnt;
 }
 
 static int has_changes(struct diff_filepair *p, struct diff_options *o,
                       regex_t *regexp, kwset_t kws)
 {
-       if (!DIFF_FILE_VALID(p->one)) {
-               if (!DIFF_FILE_VALID(p->two))
-                       return 0; /* ignore unmerged */
+       struct userdiff_driver *textconv_one = get_textconv(p->one);
+       struct userdiff_driver *textconv_two = get_textconv(p->two);
+       mmfile_t mf1, mf2;
+       int ret;
+
+       if (!o->pickaxe[0])
+               return 0;
+
+       /*
+        * If we have an unmodified pair, we know that the count will be the
+        * same and don't even have to load the blobs. Unless textconv is in
+        * play, _and_ we are using two different textconv filters (e.g.,
+        * because a pair is an exact rename with different textconv attributes
+        * for each side, which might generate different content).
+        */
+       if (textconv_one == textconv_two && diff_unmodified_pair(p))
+               return 0;
+
+       fill_one(p->one, &mf1, &textconv_one);
+       fill_one(p->two, &mf2, &textconv_two);
+
+       if (!mf1.ptr) {
+               if (!mf2.ptr)
+                       ret = 0; /* ignore unmerged */
                /* created */
-               return contains(p->two, o, regexp, kws) != 0;
-       }
-       if (!DIFF_FILE_VALID(p->two))
-               return contains(p->one, o, regexp, kws) != 0;
-       if (!diff_unmodified_pair(p)) {
-               return contains(p->one, o, regexp, kws) !=
-                      contains(p->two, o, regexp, kws);
+               ret = contains(&mf2, o, regexp, kws) != 0;
        }
-       return 0;
+       else if (!mf2.ptr) /* removed */
+               ret = contains(&mf1, o, regexp, kws) != 0;
+       else
+               ret = contains(&mf1, o, regexp, kws) !=
+                     contains(&mf2, o, regexp, kws);
+
+       if (textconv_one)
+               free(mf1.ptr);
+       if (textconv_two)
+               free(mf2.ptr);
+       diff_free_filespec_data(p->one);
+       diff_free_filespec_data(p->two);
+
+       return ret;
 }
 
 static void diffcore_pickaxe_count(struct diff_options *o)
diff --git a/dir.c b/dir.c
index 4868339..a473ca2 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -308,42 +308,69 @@ static int no_wildcard(const char *string)
        return string[simple_length(string)] == '\0';
 }
 
+void parse_exclude_pattern(const char **pattern,
+                          int *patternlen,
+                          int *flags,
+                          int *nowildcardlen)
+{
+       const char *p = *pattern;
+       size_t i, len;
+
+       *flags = 0;
+       if (*p == '!') {
+               *flags |= EXC_FLAG_NEGATIVE;
+               p++;
+       }
+       len = strlen(p);
+       if (len && p[len - 1] == '/') {
+               len--;
+               *flags |= EXC_FLAG_MUSTBEDIR;
+       }
+       for (i = 0; i < len; i++) {
+               if (p[i] == '/')
+                       break;
+       }
+       if (i == len)
+               *flags |= EXC_FLAG_NODIR;
+       *nowildcardlen = simple_length(p);
+       /*
+        * we should have excluded the trailing slash from 'p' too,
+        * but that's one more allocation. Instead just make sure
+        * nowildcardlen does not exceed real patternlen
+        */
+       if (*nowildcardlen > len)
+               *nowildcardlen = len;
+       if (*p == '*' && no_wildcard(p + 1))
+               *flags |= EXC_FLAG_ENDSWITH;
+       *pattern = p;
+       *patternlen = len;
+}
+
 void add_exclude(const char *string, const char *base,
                 int baselen, struct exclude_list *which)
 {
        struct exclude *x;
-       size_t len;
-       int to_exclude = 1;
-       int flags = 0;
+       int patternlen;
+       int flags;
+       int nowildcardlen;
 
-       if (*string == '!') {
-               to_exclude = 0;
-               string++;
-       }
-       len = strlen(string);
-       if (len && string[len - 1] == '/') {
+       parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);
+       if (flags & EXC_FLAG_MUSTBEDIR) {
                char *s;
-               x = xmalloc(sizeof(*x) + len);
+               x = xmalloc(sizeof(*x) + patternlen + 1);
                s = (char *)(x+1);
-               memcpy(s, string, len - 1);
-               s[len - 1] = '\0';
-               string = s;
+               memcpy(s, string, patternlen);
+               s[patternlen] = '\0';
                x->pattern = s;
-               flags = EXC_FLAG_MUSTBEDIR;
        } else {
                x = xmalloc(sizeof(*x));
                x->pattern = string;
        }
-       x->to_exclude = to_exclude;
-       x->patternlen = strlen(string);
+       x->patternlen = patternlen;
+       x->nowildcardlen = nowildcardlen;
        x->base = base;
        x->baselen = baselen;
        x->flags = flags;
-       if (!strchr(string, '/'))
-               x->flags |= EXC_FLAG_NODIR;
-       x->nowildcardlen = simple_length(string);
-       if (*string == '*' && no_wildcard(string+1))
-               x->flags |= EXC_FLAG_ENDSWITH;
        ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
        which->excludes[which->nr++] = x;
 }
@@ -505,6 +532,72 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
        dir->basebuf[baselen] = '\0';
 }
 
+int match_basename(const char *basename, int basenamelen,
+                  const char *pattern, int prefix, int patternlen,
+                  int flags)
+{
+       if (prefix == patternlen) {
+               if (!strcmp_icase(pattern, basename))
+                       return 1;
+       } else if (flags & EXC_FLAG_ENDSWITH) {
+               if (patternlen - 1 <= basenamelen &&
+                   !strcmp_icase(pattern + 1,
+                                 basename + basenamelen - patternlen + 1))
+                       return 1;
+       } else {
+               if (fnmatch_icase(pattern, basename, 0) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+int match_pathname(const char *pathname, int pathlen,
+                  const char *base, int baselen,
+                  const char *pattern, int prefix, int patternlen,
+                  int flags)
+{
+       const char *name;
+       int namelen;
+
+       /*
+        * match with FNM_PATHNAME; the pattern has base implicitly
+        * in front of it.
+        */
+       if (*pattern == '/') {
+               pattern++;
+               prefix--;
+       }
+
+       /*
+        * baselen does not count the trailing slash. base[] may or
+        * may not end with a trailing slash though.
+        */
+       if (pathlen < baselen + 1 ||
+           (baselen && pathname[baselen] != '/') ||
+           strncmp_icase(pathname, base, baselen))
+               return 0;
+
+       namelen = baselen ? pathlen - baselen - 1 : pathlen;
+       name = pathname + pathlen - namelen;
+
+       if (prefix) {
+               /*
+                * if the non-wildcard part is longer than the
+                * remaining pathname, surely it cannot match.
+                */
+               if (prefix > namelen)
+                       return 0;
+
+               if (strncmp_icase(pattern, name, prefix))
+                       return 0;
+               pattern += prefix;
+               name    += prefix;
+               namelen -= prefix;
+       }
+
+       return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0;
+}
+
 /* Scan the list and let the last match determine the fate.
  * Return 1 for exclude, 0 for include and -1 for undecided.
  */
@@ -519,9 +612,9 @@ int excluded_from_list(const char *pathname,
 
        for (i = el->nr - 1; 0 <= i; i--) {
                struct exclude *x = el->excludes[i];
-               const char *name, *exclude = x->pattern;
-               int to_exclude = x->to_exclude;
-               int namelen, prefix = x->nowildcardlen;
+               const char *exclude = x->pattern;
+               int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
+               int prefix = x->nowildcardlen;
 
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
@@ -531,51 +624,18 @@ int excluded_from_list(const char *pathname,
                }
 
                if (x->flags & EXC_FLAG_NODIR) {
-                       /* match basename */
-                       if (prefix == x->patternlen) {
-                               if (!strcmp_icase(exclude, basename))
-                                       return to_exclude;
-                       } else if (x->flags & EXC_FLAG_ENDSWITH) {
-                               if (x->patternlen - 1 <= pathlen &&
-                                   !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
-                                       return to_exclude;
-                       } else {
-                               if (fnmatch_icase(exclude, basename, 0) == 0)
-                                       return to_exclude;
-                       }
+                       if (match_basename(basename,
+                                          pathlen - (basename - pathname),
+                                          exclude, prefix, x->patternlen,
+                                          x->flags))
+                               return to_exclude;
                        continue;
                }
 
-               /* match with FNM_PATHNAME:
-                * exclude has base (baselen long) implicitly in front of it.
-                */
-               if (*exclude == '/') {
-                       exclude++;
-                       prefix--;
-               }
-
-               if (pathlen < x->baselen ||
-                   (x->baselen && pathname[x->baselen-1] != '/') ||
-                   strncmp_icase(pathname, x->base, x->baselen))
-                       continue;
-
-               namelen = x->baselen ? pathlen - x->baselen : pathlen;
-               name = pathname + pathlen  - namelen;
-
-               /* if the non-wildcard part is longer than the
-                  remaining pathname, surely it cannot match */
-               if (prefix > namelen)
-                       continue;
-
-               if (prefix) {
-                       if (strncmp_icase(exclude, name, prefix))
-                               continue;
-                       exclude += prefix;
-                       name    += prefix;
-                       namelen -= prefix;
-               }
-
-               if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME))
+               assert(x->baselen == 0 || x->base[x->baselen - 1] == '/');
+               if (match_pathname(pathname, pathlen,
+                                  x->base, x->baselen ? x->baselen - 1 : 0,
+                                  exclude, prefix, x->patternlen, x->flags))
                        return to_exclude;
        }
        return -1; /* undecided */
@@ -672,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);
@@ -774,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
@@ -789,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.
@@ -801,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:
@@ -826,7 +894,23 @@ 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;
@@ -834,6 +918,45 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
 }
 
 /*
+ * 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,
  * return true, and we'll skip it early.
@@ -971,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;
@@ -1001,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;
 }
diff --git a/dir.h b/dir.h
index 893465a..f5c89e3 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -11,6 +11,7 @@ struct dir_entry {
 #define EXC_FLAG_NODIR 1
 #define EXC_FLAG_ENDSWITH 4
 #define EXC_FLAG_MUSTBEDIR 8
+#define EXC_FLAG_NEGATIVE 16
 
 struct exclude_list {
        int nr;
@@ -21,7 +22,6 @@ struct exclude_list {
                int nowildcardlen;
                const char *base;
                int baselen;
-               int to_exclude;
                int flags;
        } **excludes;
 };
@@ -81,6 +81,16 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas
 struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
 
 /*
+ * these implement the matching logic for dir.c:excluded_from_list and
+ * attr.c:path_matches()
+ */
+extern int match_basename(const char *, int,
+                         const char *, int, int, int);
+extern int match_pathname(const char *, int,
+                         const char *, int,
+                         const char *, int, int, int);
+
+/*
  * The excluded() API is meant for callers that check each level of leading
  * directory hierarchies with excluded() to avoid recursing into excluded
  * directories.  Callers that do not do so should use this API instead.
@@ -97,6 +107,7 @@ extern int path_excluded(struct path_exclude_check *, const char *, int namelen,
 extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
                                          char **buf_p, struct exclude_list *which, int check_index);
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
+extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);
 extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
 extern void free_excludes(struct exclude_list *el);
index d834003..27bdecd 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);
        }
diff --git a/fetch-pack.c b/fetch-pack.c
new file mode 100644 (file)
index 0000000..099ff4d
--- /dev/null
@@ -0,0 +1,951 @@
+#include "cache.h"
+#include "refs.h"
+#include "pkt-line.h"
+#include "commit.h"
+#include "tag.h"
+#include "exec_cmd.h"
+#include "pack.h"
+#include "sideband.h"
+#include "fetch-pack.h"
+#include "remote.h"
+#include "run-command.h"
+#include "transport.h"
+#include "version.h"
+
+static int transfer_unpack_limit = -1;
+static int fetch_unpack_limit = -1;
+static int unpack_limit = 100;
+static int prefer_ofs_delta = 1;
+static int no_done;
+static int fetch_fsck_objects = -1;
+static int transfer_fsck_objects = -1;
+static int agent_supported;
+
+#define COMPLETE       (1U << 0)
+#define COMMON         (1U << 1)
+#define COMMON_REF     (1U << 2)
+#define SEEN           (1U << 3)
+#define POPPED         (1U << 4)
+
+static int marked;
+
+/*
+ * After sending this many "have"s if we do not get any new ACK , we
+ * give up traversing our history.
+ */
+#define MAX_IN_VAIN 256
+
+static struct commit_list *rev_list;
+static int non_common_revs, multi_ack, use_sideband;
+
+static void rev_list_push(struct commit *commit, int mark)
+{
+       if (!(commit->object.flags & mark)) {
+               commit->object.flags |= mark;
+
+               if (!(commit->object.parsed))
+                       if (parse_commit(commit))
+                               return;
+
+               commit_list_insert_by_date(commit, &rev_list);
+
+               if (!(commit->object.flags & COMMON))
+                       non_common_revs++;
+       }
+}
+
+static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+       struct object *o = deref_tag(parse_object(sha1), refname, 0);
+
+       if (o && o->type == OBJ_COMMIT)
+               rev_list_push((struct commit *)o, SEEN);
+
+       return 0;
+}
+
+static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+       struct object *o = deref_tag(parse_object(sha1), refname, 0);
+
+       if (o && o->type == OBJ_COMMIT)
+               clear_commit_marks((struct commit *)o,
+                                  COMMON | COMMON_REF | SEEN | POPPED);
+       return 0;
+}
+
+/*
+   This function marks a rev and its ancestors as common.
+   In some cases, it is desirable to mark only the ancestors (for example
+   when only the server does not yet know that they are common).
+*/
+
+static void mark_common(struct commit *commit,
+               int ancestors_only, int dont_parse)
+{
+       if (commit != NULL && !(commit->object.flags & COMMON)) {
+               struct object *o = (struct object *)commit;
+
+               if (!ancestors_only)
+                       o->flags |= COMMON;
+
+               if (!(o->flags & SEEN))
+                       rev_list_push(commit, SEEN);
+               else {
+                       struct commit_list *parents;
+
+                       if (!ancestors_only && !(o->flags & POPPED))
+                               non_common_revs--;
+                       if (!o->parsed && !dont_parse)
+                               if (parse_commit(commit))
+                                       return;
+
+                       for (parents = commit->parents;
+                                       parents;
+                                       parents = parents->next)
+                               mark_common(parents->item, 0, dont_parse);
+               }
+       }
+}
+
+/*
+  Get the next rev to send, ignoring the common.
+*/
+
+static const unsigned char *get_rev(void)
+{
+       struct commit *commit = NULL;
+
+       while (commit == NULL) {
+               unsigned int mark;
+               struct commit_list *parents;
+
+               if (rev_list == NULL || non_common_revs == 0)
+                       return NULL;
+
+               commit = rev_list->item;
+               if (!commit->object.parsed)
+                       parse_commit(commit);
+               parents = commit->parents;
+
+               commit->object.flags |= POPPED;
+               if (!(commit->object.flags & COMMON))
+                       non_common_revs--;
+
+               if (commit->object.flags & COMMON) {
+                       /* do not send "have", and ignore ancestors */
+                       commit = NULL;
+                       mark = COMMON | SEEN;
+               } else if (commit->object.flags & COMMON_REF)
+                       /* send "have", and ignore ancestors */
+                       mark = COMMON | SEEN;
+               else
+                       /* send "have", also for its ancestors */
+                       mark = SEEN;
+
+               while (parents) {
+                       if (!(parents->item->object.flags & SEEN))
+                               rev_list_push(parents->item, mark);
+                       if (mark & COMMON)
+                               mark_common(parents->item, 1, 0);
+                       parents = parents->next;
+               }
+
+               rev_list = rev_list->next;
+       }
+
+       return commit->object.sha1;
+}
+
+enum ack_type {
+       NAK = 0,
+       ACK,
+       ACK_continue,
+       ACK_common,
+       ACK_ready
+};
+
+static void consume_shallow_list(struct fetch_pack_args *args, int fd)
+{
+       if (args->stateless_rpc && args->depth > 0) {
+               /* If we sent a depth we will get back "duplicate"
+                * shallow and unshallow commands every time there
+                * is a block of have lines exchanged.
+                */
+               char line[1000];
+               while (packet_read_line(fd, line, sizeof(line))) {
+                       if (!prefixcmp(line, "shallow "))
+                               continue;
+                       if (!prefixcmp(line, "unshallow "))
+                               continue;
+                       die("git fetch-pack: expected shallow list");
+               }
+       }
+}
+
+struct write_shallow_data {
+       struct strbuf *out;
+       int use_pack_protocol;
+       int count;
+};
+
+static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
+{
+       struct write_shallow_data *data = cb_data;
+       const char *hex = sha1_to_hex(graft->sha1);
+       data->count++;
+       if (data->use_pack_protocol)
+               packet_buf_write(data->out, "shallow %s", hex);
+       else {
+               strbuf_addstr(data->out, hex);
+               strbuf_addch(data->out, '\n');
+       }
+       return 0;
+}
+
+static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
+{
+       struct write_shallow_data data;
+       data.out = out;
+       data.use_pack_protocol = use_pack_protocol;
+       data.count = 0;
+       for_each_commit_graft(write_one_shallow, &data);
+       return data.count;
+}
+
+static enum ack_type get_ack(int fd, unsigned char *result_sha1)
+{
+       static char line[1000];
+       int len = packet_read_line(fd, line, sizeof(line));
+
+       if (!len)
+               die("git fetch-pack: expected ACK/NAK, got EOF");
+       if (line[len-1] == '\n')
+               line[--len] = 0;
+       if (!strcmp(line, "NAK"))
+               return NAK;
+       if (!prefixcmp(line, "ACK ")) {
+               if (!get_sha1_hex(line+4, result_sha1)) {
+                       if (strstr(line+45, "continue"))
+                               return ACK_continue;
+                       if (strstr(line+45, "common"))
+                               return ACK_common;
+                       if (strstr(line+45, "ready"))
+                               return ACK_ready;
+                       return ACK;
+               }
+       }
+       die("git fetch_pack: expected ACK/NAK, got '%s'", line);
+}
+
+static void send_request(struct fetch_pack_args *args,
+                        int fd, struct strbuf *buf)
+{
+       if (args->stateless_rpc) {
+               send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
+               packet_flush(fd);
+       } else
+               safe_write(fd, buf->buf, buf->len);
+}
+
+static void insert_one_alternate_ref(const struct ref *ref, void *unused)
+{
+       rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
+}
+
+#define INITIAL_FLUSH 16
+#define PIPESAFE_FLUSH 32
+#define LARGE_FLUSH 1024
+
+static int next_flush(struct fetch_pack_args *args, int count)
+{
+       int flush_limit = args->stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH;
+
+       if (count < flush_limit)
+               count <<= 1;
+       else
+               count += flush_limit;
+       return count;
+}
+
+static int find_common(struct fetch_pack_args *args,
+                      int fd[2], unsigned char *result_sha1,
+                      struct ref *refs)
+{
+       int fetching;
+       int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
+       const unsigned char *sha1;
+       unsigned in_vain = 0;
+       int got_continue = 0;
+       int got_ready = 0;
+       struct strbuf req_buf = STRBUF_INIT;
+       size_t state_len = 0;
+
+       if (args->stateless_rpc && multi_ack == 1)
+               die("--stateless-rpc requires multi_ack_detailed");
+       if (marked)
+               for_each_ref(clear_marks, NULL);
+       marked = 1;
+
+       for_each_ref(rev_list_insert_ref, NULL);
+       for_each_alternate_ref(insert_one_alternate_ref, NULL);
+
+       fetching = 0;
+       for ( ; refs ; refs = refs->next) {
+               unsigned char *remote = refs->old_sha1;
+               const char *remote_hex;
+               struct object *o;
+
+               /*
+                * If that object is complete (i.e. it is an ancestor of a
+                * local ref), we tell them we have it but do not have to
+                * tell them about its ancestors, which they already know
+                * about.
+                *
+                * We use lookup_object here because we are only
+                * interested in the case we *know* the object is
+                * reachable and we have already scanned it.
+                */
+               if (((o = lookup_object(remote)) != NULL) &&
+                               (o->flags & COMPLETE)) {
+                       continue;
+               }
+
+               remote_hex = sha1_to_hex(remote);
+               if (!fetching) {
+                       struct strbuf c = STRBUF_INIT;
+                       if (multi_ack == 2)     strbuf_addstr(&c, " multi_ack_detailed");
+                       if (multi_ack == 1)     strbuf_addstr(&c, " multi_ack");
+                       if (no_done)            strbuf_addstr(&c, " no-done");
+                       if (use_sideband == 2)  strbuf_addstr(&c, " side-band-64k");
+                       if (use_sideband == 1)  strbuf_addstr(&c, " side-band");
+                       if (args->use_thin_pack) strbuf_addstr(&c, " thin-pack");
+                       if (args->no_progress)   strbuf_addstr(&c, " no-progress");
+                       if (args->include_tag)   strbuf_addstr(&c, " include-tag");
+                       if (prefer_ofs_delta)   strbuf_addstr(&c, " ofs-delta");
+                       if (agent_supported)    strbuf_addf(&c, " agent=%s",
+                                                           git_user_agent_sanitized());
+                       packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
+                       strbuf_release(&c);
+               } else
+                       packet_buf_write(&req_buf, "want %s\n", remote_hex);
+               fetching++;
+       }
+
+       if (!fetching) {
+               strbuf_release(&req_buf);
+               packet_flush(fd[1]);
+               return 1;
+       }
+
+       if (is_repository_shallow())
+               write_shallow_commits(&req_buf, 1);
+       if (args->depth > 0)
+               packet_buf_write(&req_buf, "deepen %d", args->depth);
+       packet_buf_flush(&req_buf);
+       state_len = req_buf.len;
+
+       if (args->depth > 0) {
+               char line[1024];
+               unsigned char sha1[20];
+
+               send_request(args, fd[1], &req_buf);
+               while (packet_read_line(fd[0], line, sizeof(line))) {
+                       if (!prefixcmp(line, "shallow ")) {
+                               if (get_sha1_hex(line + 8, sha1))
+                                       die("invalid shallow line: %s", line);
+                               register_shallow(sha1);
+                               continue;
+                       }
+                       if (!prefixcmp(line, "unshallow ")) {
+                               if (get_sha1_hex(line + 10, sha1))
+                                       die("invalid unshallow line: %s", line);
+                               if (!lookup_object(sha1))
+                                       die("object not found: %s", line);
+                               /* make sure that it is parsed as shallow */
+                               if (!parse_object(sha1))
+                                       die("error in object: %s", line);
+                               if (unregister_shallow(sha1))
+                                       die("no shallow found: %s", line);
+                               continue;
+                       }
+                       die("expected shallow/unshallow, got %s", line);
+               }
+       } else if (!args->stateless_rpc)
+               send_request(args, fd[1], &req_buf);
+
+       if (!args->stateless_rpc) {
+               /* If we aren't using the stateless-rpc interface
+                * we don't need to retain the headers.
+                */
+               strbuf_setlen(&req_buf, 0);
+               state_len = 0;
+       }
+
+       flushes = 0;
+       retval = -1;
+       while ((sha1 = get_rev())) {
+               packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1));
+               if (args->verbose)
+                       fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
+               in_vain++;
+               if (flush_at <= ++count) {
+                       int ack;
+
+                       packet_buf_flush(&req_buf);
+                       send_request(args, fd[1], &req_buf);
+                       strbuf_setlen(&req_buf, state_len);
+                       flushes++;
+                       flush_at = next_flush(args, count);
+
+                       /*
+                        * We keep one window "ahead" of the other side, and
+                        * will wait for an ACK only on the next one
+                        */
+                       if (!args->stateless_rpc && count == INITIAL_FLUSH)
+                               continue;
+
+                       consume_shallow_list(args, fd[0]);
+                       do {
+                               ack = get_ack(fd[0], result_sha1);
+                               if (args->verbose && ack)
+                                       fprintf(stderr, "got ack %d %s\n", ack,
+                                                       sha1_to_hex(result_sha1));
+                               switch (ack) {
+                               case ACK:
+                                       flushes = 0;
+                                       multi_ack = 0;
+                                       retval = 0;
+                                       goto done;
+                               case ACK_common:
+                               case ACK_ready:
+                               case ACK_continue: {
+                                       struct commit *commit =
+                                               lookup_commit(result_sha1);
+                                       if (!commit)
+                                               die("invalid commit %s", sha1_to_hex(result_sha1));
+                                       if (args->stateless_rpc
+                                        && ack == ACK_common
+                                        && !(commit->object.flags & COMMON)) {
+                                               /* We need to replay the have for this object
+                                                * on the next RPC request so the peer knows
+                                                * it is in common with us.
+                                                */
+                                               const char *hex = sha1_to_hex(result_sha1);
+                                               packet_buf_write(&req_buf, "have %s\n", hex);
+                                               state_len = req_buf.len;
+                                       }
+                                       mark_common(commit, 0, 1);
+                                       retval = 0;
+                                       in_vain = 0;
+                                       got_continue = 1;
+                                       if (ack == ACK_ready) {
+                                               rev_list = NULL;
+                                               got_ready = 1;
+                                       }
+                                       break;
+                                       }
+                               }
+                       } while (ack);
+                       flushes--;
+                       if (got_continue && MAX_IN_VAIN < in_vain) {
+                               if (args->verbose)
+                                       fprintf(stderr, "giving up\n");
+                               break; /* give up */
+                       }
+               }
+       }
+done:
+       if (!got_ready || !no_done) {
+               packet_buf_write(&req_buf, "done\n");
+               send_request(args, fd[1], &req_buf);
+       }
+       if (args->verbose)
+               fprintf(stderr, "done\n");
+       if (retval != 0) {
+               multi_ack = 0;
+               flushes++;
+       }
+       strbuf_release(&req_buf);
+
+       consume_shallow_list(args, fd[0]);
+       while (flushes || multi_ack) {
+               int ack = get_ack(fd[0], result_sha1);
+               if (ack) {
+                       if (args->verbose)
+                               fprintf(stderr, "got ack (%d) %s\n", ack,
+                                       sha1_to_hex(result_sha1));
+                       if (ack == ACK)
+                               return 0;
+                       multi_ack = 1;
+                       continue;
+               }
+               flushes--;
+       }
+       /* it is no error to fetch into a completely empty repo */
+       return count ? retval : 0;
+}
+
+static struct commit_list *complete;
+
+static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+       struct object *o = parse_object(sha1);
+
+       while (o && o->type == OBJ_TAG) {
+               struct tag *t = (struct tag *) o;
+               if (!t->tagged)
+                       break; /* broken repository */
+               o->flags |= COMPLETE;
+               o = parse_object(t->tagged->sha1);
+       }
+       if (o && o->type == OBJ_COMMIT) {
+               struct commit *commit = (struct commit *)o;
+               if (!(commit->object.flags & COMPLETE)) {
+                       commit->object.flags |= COMPLETE;
+                       commit_list_insert_by_date(commit, &complete);
+               }
+       }
+       return 0;
+}
+
+static void mark_recent_complete_commits(struct fetch_pack_args *args,
+                                        unsigned long cutoff)
+{
+       while (complete && cutoff <= complete->item->date) {
+               if (args->verbose)
+                       fprintf(stderr, "Marking %s as complete\n",
+                               sha1_to_hex(complete->item->object.sha1));
+               pop_most_recent_commit(&complete, COMPLETE);
+       }
+}
+
+static int non_matching_ref(struct string_list_item *item, void *unused)
+{
+       if (item->util) {
+               item->util = NULL;
+               return 0;
+       }
+       else
+               return 1;
+}
+
+static void filter_refs(struct fetch_pack_args *args,
+                       struct ref **refs, struct string_list *sought)
+{
+       struct ref *newlist = NULL;
+       struct ref **newtail = &newlist;
+       struct ref *ref, *next;
+       int sought_pos;
+
+       sought_pos = 0;
+       for (ref = *refs; ref; ref = next) {
+               int keep = 0;
+               next = ref->next;
+               if (!memcmp(ref->name, "refs/", 5) &&
+                   check_refname_format(ref->name + 5, 0))
+                       ; /* trash */
+               else {
+                       while (sought_pos < sought->nr) {
+                               int cmp = strcmp(ref->name, sought->items[sought_pos].string);
+                               if (cmp < 0)
+                                       break; /* definitely do not have it */
+                               else if (cmp == 0) {
+                                       keep = 1; /* definitely have it */
+                                       sought->items[sought_pos++].util = "matched";
+                                       break;
+                               }
+                               else
+                                       sought_pos++; /* might have it; keep looking */
+                       }
+               }
+
+               if (! keep && args->fetch_all &&
+                   (!args->depth || prefixcmp(ref->name, "refs/tags/")))
+                       keep = 1;
+
+               if (keep) {
+                       *newtail = ref;
+                       ref->next = NULL;
+                       newtail = &ref->next;
+               } else {
+                       free(ref);
+               }
+       }
+
+       filter_string_list(sought, 0, non_matching_ref, NULL);
+       *refs = newlist;
+}
+
+static void mark_alternate_complete(const struct ref *ref, void *unused)
+{
+       mark_complete(NULL, ref->old_sha1, 0, NULL);
+}
+
+static int everything_local(struct fetch_pack_args *args,
+                           struct ref **refs, struct string_list *sought)
+{
+       struct ref *ref;
+       int retval;
+       unsigned long cutoff = 0;
+
+       save_commit_buffer = 0;
+
+       for (ref = *refs; ref; ref = ref->next) {
+               struct object *o;
+
+               o = parse_object(ref->old_sha1);
+               if (!o)
+                       continue;
+
+               /* We already have it -- which may mean that we were
+                * in sync with the other side at some time after
+                * that (it is OK if we guess wrong here).
+                */
+               if (o->type == OBJ_COMMIT) {
+                       struct commit *commit = (struct commit *)o;
+                       if (!cutoff || cutoff < commit->date)
+                               cutoff = commit->date;
+               }
+       }
+
+       if (!args->depth) {
+               for_each_ref(mark_complete, NULL);
+               for_each_alternate_ref(mark_alternate_complete, NULL);
+               if (cutoff)
+                       mark_recent_complete_commits(args, cutoff);
+       }
+
+       /*
+        * Mark all complete remote refs as common refs.
+        * Don't mark them common yet; the server has to be told so first.
+        */
+       for (ref = *refs; ref; ref = ref->next) {
+               struct object *o = deref_tag(lookup_object(ref->old_sha1),
+                                            NULL, 0);
+
+               if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
+                       continue;
+
+               if (!(o->flags & SEEN)) {
+                       rev_list_push((struct commit *)o, COMMON_REF | SEEN);
+
+                       mark_common((struct commit *)o, 1, 1);
+               }
+       }
+
+       filter_refs(args, refs, sought);
+
+       for (retval = 1, ref = *refs; ref ; ref = ref->next) {
+               const unsigned char *remote = ref->old_sha1;
+               unsigned char local[20];
+               struct object *o;
+
+               o = lookup_object(remote);
+               if (!o || !(o->flags & COMPLETE)) {
+                       retval = 0;
+                       if (!args->verbose)
+                               continue;
+                       fprintf(stderr,
+                               "want %s (%s)\n", sha1_to_hex(remote),
+                               ref->name);
+                       continue;
+               }
+
+               hashcpy(ref->new_sha1, local);
+               if (!args->verbose)
+                       continue;
+               fprintf(stderr,
+                       "already have %s (%s)\n", sha1_to_hex(remote),
+                       ref->name);
+       }
+       return retval;
+}
+
+static int sideband_demux(int in, int out, void *data)
+{
+       int *xd = data;
+
+       int ret = recv_sideband("fetch-pack", xd[0], out);
+       close(out);
+       return ret;
+}
+
+static int get_pack(struct fetch_pack_args *args,
+                   int xd[2], char **pack_lockfile)
+{
+       struct async demux;
+       const char *argv[20];
+       char keep_arg[256];
+       char hdr_arg[256];
+       const char **av;
+       int do_keep = args->keep_pack;
+       struct child_process cmd;
+
+       memset(&demux, 0, sizeof(demux));
+       if (use_sideband) {
+               /* xd[] is talking with upload-pack; subprocess reads from
+                * xd[0], spits out band#2 to stderr, and feeds us band#1
+                * through demux->out.
+                */
+               demux.proc = sideband_demux;
+               demux.data = xd;
+               demux.out = -1;
+               if (start_async(&demux))
+                       die("fetch-pack: unable to fork off sideband"
+                           " demultiplexer");
+       }
+       else
+               demux.out = xd[0];
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.argv = argv;
+       av = argv;
+       *hdr_arg = 0;
+       if (!args->keep_pack && unpack_limit) {
+               struct pack_header header;
+
+               if (read_pack_header(demux.out, &header))
+                       die("protocol error: bad pack header");
+               snprintf(hdr_arg, sizeof(hdr_arg),
+                        "--pack_header=%"PRIu32",%"PRIu32,
+                        ntohl(header.hdr_version), ntohl(header.hdr_entries));
+               if (ntohl(header.hdr_entries) < unpack_limit)
+                       do_keep = 0;
+               else
+                       do_keep = 1;
+       }
+
+       if (do_keep) {
+               if (pack_lockfile)
+                       cmd.out = -1;
+               *av++ = "index-pack";
+               *av++ = "--stdin";
+               if (!args->quiet && !args->no_progress)
+                       *av++ = "-v";
+               if (args->use_thin_pack)
+                       *av++ = "--fix-thin";
+               if (args->lock_pack || unpack_limit) {
+                       int s = sprintf(keep_arg,
+                                       "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid());
+                       if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
+                               strcpy(keep_arg + s, "localhost");
+                       *av++ = keep_arg;
+               }
+       }
+       else {
+               *av++ = "unpack-objects";
+               if (args->quiet || args->no_progress)
+                       *av++ = "-q";
+       }
+       if (*hdr_arg)
+               *av++ = hdr_arg;
+       if (fetch_fsck_objects >= 0
+           ? fetch_fsck_objects
+           : transfer_fsck_objects >= 0
+           ? transfer_fsck_objects
+           : 0)
+               *av++ = "--strict";
+       *av++ = NULL;
+
+       cmd.in = demux.out;
+       cmd.git_cmd = 1;
+       if (start_command(&cmd))
+               die("fetch-pack: unable to fork off %s", argv[0]);
+       if (do_keep && pack_lockfile) {
+               *pack_lockfile = index_pack_lockfile(cmd.out);
+               close(cmd.out);
+       }
+
+       if (finish_command(&cmd))
+               die("%s failed", argv[0]);
+       if (use_sideband && finish_async(&demux))
+               die("error in sideband demultiplexer");
+       return 0;
+}
+
+static struct ref *do_fetch_pack(struct fetch_pack_args *args,
+                                int fd[2],
+                                const struct ref *orig_ref,
+                                struct string_list *sought,
+                                char **pack_lockfile)
+{
+       struct ref *ref = copy_ref_list(orig_ref);
+       unsigned char sha1[20];
+       const char *agent_feature;
+       int agent_len;
+
+       sort_ref_list(&ref, ref_compare_name);
+
+       if (is_repository_shallow() && !server_supports("shallow"))
+               die("Server does not support shallow clients");
+       if (server_supports("multi_ack_detailed")) {
+               if (args->verbose)
+                       fprintf(stderr, "Server supports multi_ack_detailed\n");
+               multi_ack = 2;
+               if (server_supports("no-done")) {
+                       if (args->verbose)
+                               fprintf(stderr, "Server supports no-done\n");
+                       if (args->stateless_rpc)
+                               no_done = 1;
+               }
+       }
+       else if (server_supports("multi_ack")) {
+               if (args->verbose)
+                       fprintf(stderr, "Server supports multi_ack\n");
+               multi_ack = 1;
+       }
+       if (server_supports("side-band-64k")) {
+               if (args->verbose)
+                       fprintf(stderr, "Server supports side-band-64k\n");
+               use_sideband = 2;
+       }
+       else if (server_supports("side-band")) {
+               if (args->verbose)
+                       fprintf(stderr, "Server supports side-band\n");
+               use_sideband = 1;
+       }
+       if (!server_supports("thin-pack"))
+               args->use_thin_pack = 0;
+       if (!server_supports("no-progress"))
+               args->no_progress = 0;
+       if (!server_supports("include-tag"))
+               args->include_tag = 0;
+       if (server_supports("ofs-delta")) {
+               if (args->verbose)
+                       fprintf(stderr, "Server supports ofs-delta\n");
+       } else
+               prefer_ofs_delta = 0;
+
+       if ((agent_feature = server_feature_value("agent", &agent_len))) {
+               agent_supported = 1;
+               if (args->verbose && agent_len)
+                       fprintf(stderr, "Server version is %.*s\n",
+                               agent_len, agent_feature);
+       }
+
+       if (everything_local(args, &ref, sought)) {
+               packet_flush(fd[1]);
+               goto all_done;
+       }
+       if (find_common(args, fd, sha1, ref) < 0)
+               if (!args->keep_pack)
+                       /* When cloning, it is not unusual to have
+                        * no common commit.
+                        */
+                       warning("no common commits");
+
+       if (args->stateless_rpc)
+               packet_flush(fd[1]);
+       if (get_pack(args, fd, pack_lockfile))
+               die("git fetch-pack: fetch failed.");
+
+ all_done:
+       return ref;
+}
+
+static int fetch_pack_config(const char *var, const char *value, void *cb)
+{
+       if (strcmp(var, "fetch.unpacklimit") == 0) {
+               fetch_unpack_limit = git_config_int(var, value);
+               return 0;
+       }
+
+       if (strcmp(var, "transfer.unpacklimit") == 0) {
+               transfer_unpack_limit = git_config_int(var, value);
+               return 0;
+       }
+
+       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
+               prefer_ofs_delta = git_config_bool(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "fetch.fsckobjects")) {
+               fetch_fsck_objects = git_config_bool(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "transfer.fsckobjects")) {
+               transfer_fsck_objects = git_config_bool(var, value);
+               return 0;
+       }
+
+       return git_default_config(var, value, cb);
+}
+
+static struct lock_file lock;
+
+static void fetch_pack_setup(void)
+{
+       static int did_setup;
+       if (did_setup)
+               return;
+       git_config(fetch_pack_config, NULL);
+       if (0 <= transfer_unpack_limit)
+               unpack_limit = transfer_unpack_limit;
+       else if (0 <= fetch_unpack_limit)
+               unpack_limit = fetch_unpack_limit;
+       did_setup = 1;
+}
+
+struct ref *fetch_pack(struct fetch_pack_args *args,
+                      int fd[], struct child_process *conn,
+                      const struct ref *ref,
+                      const char *dest,
+                      struct string_list *sought,
+                      char **pack_lockfile)
+{
+       struct stat st;
+       struct ref *ref_cpy;
+
+       fetch_pack_setup();
+       if (args->depth > 0) {
+               if (stat(git_path("shallow"), &st))
+                       st.st_mtime = 0;
+       }
+
+       if (sought->nr) {
+               sort_string_list(sought);
+               string_list_remove_duplicates(sought, 0);
+       }
+
+       if (!ref) {
+               packet_flush(fd[1]);
+               die("no matching remote head");
+       }
+       ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);
+
+       if (args->depth > 0) {
+               struct cache_time mtime;
+               struct strbuf sb = STRBUF_INIT;
+               char *shallow = git_path("shallow");
+               int fd;
+
+               mtime.sec = st.st_mtime;
+               mtime.nsec = ST_MTIME_NSEC(st);
+               if (stat(shallow, &st)) {
+                       if (mtime.sec)
+                               die("shallow file was removed during fetch");
+               } else if (st.st_mtime != mtime.sec
+#ifdef USE_NSEC
+                               || ST_MTIME_NSEC(st) != mtime.nsec
+#endif
+                         )
+                       die("shallow file was changed during fetch");
+
+               fd = hold_lock_file_for_update(&lock, shallow,
+                                              LOCK_DIE_ON_ERROR);
+               if (!write_shallow_commits(&sb, 0)
+                || write_in_full(fd, sb.buf, sb.len) != sb.len) {
+                       unlink_or_warn(shallow);
+                       rollback_lock_file(&lock);
+               } else {
+                       commit_lock_file(&lock);
+               }
+               strbuf_release(&sb);
+       }
+
+       reprepare_packed_git();
+       return ref_cpy;
+}
index c682d34..202130f 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 2fbf1fd..590d5d3 100644 (file)
@@ -506,6 +506,7 @@ extern const char tolower_trans_tbl[256];
 #undef isdigit
 #undef isalpha
 #undef isalnum
+#undef isprint
 #undef islower
 #undef isupper
 #undef tolower
@@ -523,6 +524,7 @@ extern unsigned char sane_ctype[256];
 #define isdigit(x) sane_istest(x,GIT_DIGIT)
 #define isalpha(x) sane_istest(x,GIT_ALPHA)
 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e)
 #define islower(x) sane_iscase(x, 1)
 #define isupper(x) sane_iscase(x, 0)
 #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
@@ -635,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 8032f23..0a31ebd 100755 (executable)
@@ -24,14 +24,14 @@ use File::Basename qw(basename dirname);
 use Time::Local;
 use IO::Socket;
 use IO::Pipe;
-use POSIX qw(strftime dup2 ENOENT);
+use POSIX qw(strftime tzset dup2 ENOENT);
 use IPC::Open2;
 
 $SIG{'PIPE'}="IGNORE";
-$ENV{'TZ'}="UTC";
+set_timezone('UTC');
 
 our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R);
-my (%conv_author_name, %conv_author_email);
+my (%conv_author_name, %conv_author_email, %conv_author_tz);
 
 sub usage(;$) {
        my $msg = shift;
@@ -59,6 +59,14 @@ sub read_author_info($) {
                        $conv_author_name{$user} = $2;
                        $conv_author_email{$user} = $3;
                }
+               # or with an optional timezone:
+               #   spawn=Simon Pawn <spawn@frog-pond.org> America/Chicago
+               elsif (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*(\S+?)\s*$/) {
+                       $user = $1;
+                       $conv_author_name{$user} = $2;
+                       $conv_author_email{$user} = $3;
+                       $conv_author_tz{$user} = $4;
+               }
                # However, we also read from CVSROOT/users format
                # to ease migration.
                elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) {
@@ -84,11 +92,22 @@ sub write_author_info($) {
          die("Failed to open $file for writing: $!");
 
        foreach (keys %conv_author_name) {
-               print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n";
+               print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>";
+               print $f " $conv_author_tz{$_}" if ($conv_author_tz{$_});
+               print $f "\n";
        }
        close ($f);
 }
 
+# Versions of perl before 5.10.0 may not automatically check $TZ each
+# time localtime is run (most platforms will do so only the first time).
+# We can work around this by using tzset() to update the internal
+# variable whenever we change the environment.
+sub set_timezone {
+       $ENV{TZ} = shift;
+       tzset();
+}
+
 # convert getopts specs for use by git config
 my %longmap = (
        'A:' => 'authors-file',
@@ -795,7 +814,7 @@ sub write_tree () {
        return $tree;
 }
 
-my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
+my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg);
 my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
 
 # commits that cvsps cannot place anywhere...
@@ -844,7 +863,9 @@ sub commit {
                }
        }
 
-       my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
+       set_timezone($author_tz);
+       my $commit_date = strftime("%s %z", localtime($date));
+       set_timezone('UTC');
        $ENV{GIT_AUTHOR_NAME} = $author_name;
        $ENV{GIT_AUTHOR_EMAIL} = $author_email;
        $ENV{GIT_AUTHOR_DATE} = $commit_date;
@@ -945,12 +966,14 @@ while (<CVS>) {
                }
                $state=3;
        } elsif ($state == 3 and s/^Author:\s+//) {
+               $author_tz = "UTC";
                s/\s+$//;
                if (/^(.*?)\s+<(.*)>/) {
                    ($author_name, $author_email) = ($1, $2);
                } elsif ($conv_author_name{$_}) {
                        $author_name = $conv_author_name{$_};
                        $author_email = $conv_author_email{$_};
+                       $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_});
                } else {
                    $author_name = $author_email = $_;
                }
index b8eddab..c5ebfa0 100755 (executable)
@@ -51,6 +51,10 @@ $| = 1;
 
 #### Definition and mappings of functions ####
 
+# NOTE: Despite the existence of req_CATCHALL and req_EMPTY unimplemented
+#  requests, this list is incomplete.  It is missing many rarer/optional
+#  requests.  Perhaps some clients require a claim of support for
+#  these specific requests for main functionality to work?
 my $methods = {
     'Root'            => \&req_Root,
     'Valid-responses' => \&req_Validresponses,
@@ -80,7 +84,6 @@ my $methods = {
     'noop'            => \&req_EMPTY,
     'annotate'        => \&req_annotate,
     'Global_option'   => \&req_Globaloption,
-    #'annotate'        => \&req_CATCHALL,
 };
 
 ##############################################
@@ -499,7 +502,7 @@ sub req_Entry
 
     #$log->debug("req_Entry : $data");
 
-    my @data = split(/\//, $data);
+    my @data = split(/\//, $data, -1);
 
     $state->{entries}{$state->{directory}.$data[1]} = {
         revision    => $data[2],
@@ -540,8 +543,6 @@ sub req_add
     my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
     $updater->update();
 
-    argsfromdir($updater);
-
     my $addcount = 0;
 
     foreach my $filename ( @{$state->{args}} )
@@ -551,10 +552,10 @@ sub req_add
         my $meta = $updater->getmeta($filename);
         my $wrev = revparse($filename);
 
-        if ($wrev && $meta && ($wrev < 0))
+        if ($wrev && $meta && ($wrev=~/^-/))
         {
             # previously removed file, add back
-            $log->info("added file $filename was previously removed, send 1.$meta->{revision}");
+            $log->info("added file $filename was previously removed, send $meta->{revision}");
 
             print "MT +updated\n";
             print "MT text U \n";
@@ -571,8 +572,8 @@ sub req_add
 
                 # this is an "entries" line
                 my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
-                $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
-                print "/$filepart/1.$meta->{revision}//$kopts/\n";
+                $log->debug("/$filepart/$meta->{revision}//$kopts/");
+                print "/$filepart/$meta->{revision}//$kopts/\n";
                 # permissions
                 $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}");
                 print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n";
@@ -680,13 +681,13 @@ sub req_remove
             next;
         }
 
-        if ( defined($wrev) and $wrev < 0 )
+        if ( defined($wrev) and ($wrev=~/^-/) )
         {
             print "E cvs remove: file `$filename' already scheduled for removal\n";
             next;
         }
 
-        unless ( $wrev == $meta->{revision} )
+        unless ( $wrev eq $meta->{revision} )
         {
             # TODO : not sure if the format of this message is quite correct.
             print "E cvs remove: Up to date check failed for `$filename'\n";
@@ -701,7 +702,7 @@ sub req_remove
         print "Checked-in $dirpart\n";
         print "$filename\n";
         my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
-        print "/$filepart/-1.$wrev//$kopts/\n";
+        print "/$filepart/-$wrev//$kopts/\n";
 
         $rmcount++;
     }
@@ -992,7 +993,7 @@ sub req_co
 
         # this is an "entries" line
         my $kopts = kopts_from_path($fullName,"sha1",$git->{filehash});
-        print "/$git->{name}/1.$git->{revision}//$kopts/\n";
+        print "/$git->{name}/$git->{revision}//$kopts/\n";
         # permissions
         print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n";
 
@@ -1080,7 +1081,7 @@ sub req_update
         }
 
         my $meta;
-        if ( defined($state->{opt}{r}) and $state->{opt}{r} =~ /^1\.(\d+)/ )
+        if ( defined($state->{opt}{r}) and $state->{opt}{r} =~ /^(1\.\d+)$/ )
         {
             $meta = $updater->getmeta($filename, $1);
         } else {
@@ -1102,7 +1103,7 @@ sub req_update
        {
            $meta = {
                name => $filename,
-               revision => 0,
+               revision => '0',
                filehash => 'added'
            };
        }
@@ -1112,7 +1113,7 @@ sub req_update
         my $wrev = revparse($filename);
 
         # If the working copy is an old revision, lets get that version too for comparison.
-        if ( defined($wrev) and $wrev != $meta->{revision} )
+        if ( defined($wrev) and $wrev ne $meta->{revision} )
         {
             $oldmeta = $updater->getmeta($filename, $wrev);
         }
@@ -1123,7 +1124,7 @@ sub req_update
         # and the working copy is unmodified _and_ the user hasn't specified -C
         next if ( defined ( $wrev )
                   and defined($meta->{revision})
-                  and $wrev == $meta->{revision}
+                  and $wrev eq $meta->{revision}
                   and $state->{entries}{$filename}{unchanged}
                   and not exists ( $state->{opt}{C} ) );
 
@@ -1131,7 +1132,7 @@ sub req_update
         # but the working copy is modified, tell the client it's modified
         if ( defined ( $wrev )
              and defined($meta->{revision})
-             and $wrev == $meta->{revision}
+             and $wrev eq $meta->{revision}
              and defined($state->{entries}{$filename}{modified_hash})
              and not exists ( $state->{opt}{C} ) )
         {
@@ -1144,6 +1145,10 @@ sub req_update
 
         if ( $meta->{filehash} eq "deleted" )
         {
+            # TODO: If it has been modified in the sandbox, error out
+            #   with the appropriate message, rather than deleting a modified
+            #   file.
+
             my ( $filepart, $dirpart ) = filenamesplit($filename,1);
 
             $log->info("Removing '$filename' from working copy (no longer in the repo)");
@@ -1161,7 +1166,7 @@ sub req_update
         {
             # normal update, just send the new revision (either U=Update,
             # or A=Add, or R=Remove)
-           if ( defined($wrev) && $wrev < 0 )
+           if ( defined($wrev) && ($wrev=~/^-/) )
            {
                $log->info("Tell the client the file is scheduled for removal");
                print "MT text R \n";
@@ -1169,7 +1174,8 @@ sub req_update
                 print "MT newline\n";
                next;
            }
-           elsif ( (!defined($wrev) || $wrev == 0) && (!defined($meta->{revision}) || $meta->{revision} == 0) )
+           elsif ( (!defined($wrev) || $wrev eq '0') &&
+                    (!defined($meta->{revision}) || $meta->{revision} eq '0') )
            {
                $log->info("Tell the client the file is scheduled for addition");
                print "MT text A \n";
@@ -1179,7 +1185,7 @@ sub req_update
 
            }
            else {
-                $log->info("Updating '$filename' to ".$meta->{revision});
+                $log->info("UpdatingX3 '$filename' to ".$meta->{revision});
                 print "MT +updated\n";
                 print "MT text U \n";
                 print "MT fname $filename\n";
@@ -1211,8 +1217,8 @@ sub req_update
 
                # this is an "entries" line
                my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
-               $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
-               print "/$filepart/1.$meta->{revision}//$kopts/\n";
+               $log->debug("/$filepart/$meta->{revision}//$kopts/");
+               print "/$filepart/$meta->{revision}//$kopts/\n";
 
                # permissions
                $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}");
@@ -1222,7 +1228,6 @@ sub req_update
                transmitfile($meta->{filehash});
            }
         } else {
-            $log->info("Updating '$filename'");
             my ( $filepart, $dirpart ) = filenamesplit($meta->{name},1);
 
             my $mergeDir = setupTmpDir();
@@ -1237,7 +1242,7 @@ sub req_update
 
             # we need to merge with the local changes ( M=successful merge, C=conflict merge )
             $log->info("Merging $file_local, $file_old, $file_new");
-            print "M Merging differences between 1.$oldmeta->{revision} and 1.$meta->{revision} into $filename\n";
+            print "M Merging differences between $oldmeta->{revision} and $meta->{revision} into $filename\n";
 
             $log->debug("Temporary directory for merge is $mergeDir");
 
@@ -1260,8 +1265,8 @@ sub req_update
                     print $state->{CVSROOT} . "/$state->{module}/$filename\n";
                     my $kopts = kopts_from_path("$dirpart/$filepart",
                                                 "file",$mergedFile);
-                    $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
-                    print "/$filepart/1.$meta->{revision}//$kopts/\n";
+                    $log->debug("/$filepart/$meta->{revision}//$kopts/");
+                    print "/$filepart/$meta->{revision}//$kopts/\n";
                 }
             }
             elsif ( $return == 1 )
@@ -1277,7 +1282,7 @@ sub req_update
                     print $state->{CVSROOT} . "/$state->{module}/$filename\n";
                     my $kopts = kopts_from_path("$dirpart/$filepart",
                                                 "file",$mergedFile);
-                    print "/$filepart/1.$meta->{revision}/+/$kopts/\n";
+                    print "/$filepart/$meta->{revision}/+/$kopts/\n";
                 }
             }
             else
@@ -1380,11 +1385,12 @@ sub req_ci
 
         my $addflag = 0;
         my $rmflag = 0;
-        $rmflag = 1 if ( defined($wrev) and $wrev < 0 );
+        $rmflag = 1 if ( defined($wrev) and ($wrev=~/^-/) );
         $addflag = 1 unless ( -e $filename );
 
         # Do up to date checking
-        unless ( $addflag or $wrev == $meta->{revision} or ( $rmflag and -$wrev == $meta->{revision} ) )
+        unless ( $addflag or $wrev eq $meta->{revision} or
+                 ( $rmflag and $wrev eq "-$meta->{revision}" ) )
         {
             # fail everything if an up to date check fails
             print "error 1 Up to date check failed for $filename\n";
@@ -1421,7 +1427,7 @@ sub req_ci
             $log->info("Adding file '$filename'");
             system("git", "update-index", "--add", $filename);
         } else {
-            $log->info("Updating file '$filename'");
+            $log->info("UpdatingX2 file '$filename'");
             system("git", "update-index", $filename);
         }
     }
@@ -1512,7 +1518,7 @@ sub req_ci
 
         my $meta = $updater->getmeta($filename);
        unless (defined $meta->{revision}) {
-         $meta->{revision} = 1;
+         $meta->{revision} = "1.1";
        }
 
         my ( $filepart, $dirpart ) = filenamesplit($filename, 1);
@@ -1522,19 +1528,19 @@ sub req_ci
        print "M $state->{CVSROOT}/$state->{module}/$filename,v  <--  $dirpart$filepart\n";
         if ( defined $meta->{filehash} && $meta->{filehash} eq "deleted" )
         {
-            print "M new revision: delete; previous revision: 1.$oldmeta{$filename}{revision}\n";
+            print "M new revision: delete; previous revision: $oldmeta{$filename}{revision}\n";
             print "Remove-entry $dirpart\n";
             print "$filename\n";
         } else {
-            if ($meta->{revision} == 1) {
+            if ($meta->{revision} eq "1.1") {
                print "M initial revision: 1.1\n";
             } else {
-               print "M new revision: 1.$meta->{revision}; previous revision: 1.$oldmeta{$filename}{revision}\n";
+               print "M new revision: $meta->{revision}; previous revision: $oldmeta{$filename}{revision}\n";
             }
             print "Checked-in $dirpart\n";
             print "$filename\n";
             my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash});
-            print "/$filepart/1.$meta->{revision}//$kopts/\n";
+            print "/$filepart/$meta->{revision}//$kopts/\n";
         }
     }
 
@@ -1552,10 +1558,12 @@ sub req_status
     #$log->debug("status state : " . Dumper($state));
 
     # Grab a handle to the SQLite db and do any necessary updates
-    my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
+    my $updater;
+    $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
     $updater->update();
 
-    # if no files were specified, we need to work out what files we should be providing status on ...
+    # if no files were specified, we need to work out what files we should
+    # be providing status on ...
     argsfromdir($updater);
 
     # foreach file specified on the command line ...
@@ -1563,67 +1571,135 @@ sub req_status
     {
         $filename = filecleanup($filename);
 
-        next if exists($state->{opt}{l}) && index($filename, '/', length($state->{prependdir})) >= 0;
+        if ( exists($state->{opt}{l}) &&
+             index($filename, '/', length($state->{prependdir})) >= 0 )
+        {
+           next;
+        }
 
         my $meta = $updater->getmeta($filename);
         my $oldmeta = $meta;
 
         my $wrev = revparse($filename);
 
-        # If the working copy is an old revision, lets get that version too for comparison.
-        if ( defined($wrev) and $wrev != $meta->{revision} )
+        # If the working copy is an old revision, lets get that
+        # version too for comparison.
+        if ( defined($wrev) and $wrev ne $meta->{revision} )
         {
             $oldmeta = $updater->getmeta($filename, $wrev);
         }
 
         # TODO : All possible statuses aren't yet implemented
         my $status;
-        # Files are up to date if the working copy and repo copy have the same revision, and the working copy is unmodified
-        $status = "Up-to-date" if ( defined ( $wrev ) and defined($meta->{revision}) and $wrev == $meta->{revision}
-                                    and
-                                    ( ( $state->{entries}{$filename}{unchanged} and ( not defined ( $state->{entries}{$filename}{conflict} ) or $state->{entries}{$filename}{conflict} !~ /^\+=/ ) )
-                                      or ( defined($state->{entries}{$filename}{modified_hash}) and $state->{entries}{$filename}{modified_hash} eq $meta->{filehash} ) )
-                                   );
-
-        # Need checkout if the working copy has an older revision than the repo copy, and the working copy is unmodified
-        $status ||= "Needs Checkout" if ( defined ( $wrev ) and defined ( $meta->{revision} ) and $meta->{revision} > $wrev
-                                          and
-                                          ( $state->{entries}{$filename}{unchanged}
-                                            or ( defined($state->{entries}{$filename}{modified_hash}) and $state->{entries}{$filename}{modified_hash} eq $oldmeta->{filehash} ) )
-                                        );
-
-        # Need checkout if it exists in the repo but doesn't have a working copy
-        $status ||= "Needs Checkout" if ( not defined ( $wrev ) and defined ( $meta->{revision} ) );
-
-        # Locally modified if working copy and repo copy have the same revision but there are local changes
-        $status ||= "Locally Modified" if ( defined ( $wrev ) and defined($meta->{revision}) and $wrev == $meta->{revision} and $state->{entries}{$filename}{modified_filename} );
-
-        # Needs Merge if working copy revision is less than repo copy and there are local changes
-        $status ||= "Needs Merge" if ( defined ( $wrev ) and defined ( $meta->{revision} ) and $meta->{revision} > $wrev and $state->{entries}{$filename}{modified_filename} );
-
-        $status ||= "Locally Added" if ( defined ( $state->{entries}{$filename}{revision} ) and not defined ( $meta->{revision} ) );
-        $status ||= "Locally Removed" if ( defined ( $wrev ) and defined ( $meta->{revision} ) and -$wrev == $meta->{revision} );
-        $status ||= "Unresolved Conflict" if ( defined ( $state->{entries}{$filename}{conflict} ) and $state->{entries}{$filename}{conflict} =~ /^\+=/ );
-        $status ||= "File had conflicts on merge" if ( 0 );
+        # Files are up to date if the working copy and repo copy have
+        # the same revision, and the working copy is unmodified
+        if ( defined ( $wrev ) and defined($meta->{revision}) and
+             $wrev eq $meta->{revision} and
+             ( ( $state->{entries}{$filename}{unchanged} and
+                 ( not defined ( $state->{entries}{$filename}{conflict} ) or
+                   $state->{entries}{$filename}{conflict} !~ /^\+=/ ) ) or
+               ( defined($state->{entries}{$filename}{modified_hash}) and
+                 $state->{entries}{$filename}{modified_hash} eq
+                        $meta->{filehash} ) ) )
+        {
+            $status = "Up-to-date"
+        }
+
+        # Need checkout if the working copy has a different (usually
+        # older) revision than the repo copy, and the working copy is
+        # unmodified
+        if ( defined ( $wrev ) and defined ( $meta->{revision} ) and
+             $meta->{revision} ne $wrev and
+             ( $state->{entries}{$filename}{unchanged} or
+               ( defined($state->{entries}{$filename}{modified_hash}) and
+                 $state->{entries}{$filename}{modified_hash} eq
+                                $oldmeta->{filehash} ) ) )
+        {
+            $status ||= "Needs Checkout";
+        }
+
+        # Need checkout if it exists in the repo but doesn't have a working
+        # copy
+        if ( not defined ( $wrev ) and defined ( $meta->{revision} ) )
+        {
+            $status ||= "Needs Checkout";
+        }
+
+        # Locally modified if working copy and repo copy have the
+        # same revision but there are local changes
+        if ( defined ( $wrev ) and defined($meta->{revision}) and
+             $wrev eq $meta->{revision} and
+             $state->{entries}{$filename}{modified_filename} )
+        {
+            $status ||= "Locally Modified";
+        }
+
+        # Needs Merge if working copy revision is different
+        # (usually older) than repo copy and there are local changes
+        if ( defined ( $wrev ) and defined ( $meta->{revision} ) and
+             $meta->{revision} ne $wrev and
+             $state->{entries}{$filename}{modified_filename} )
+        {
+            $status ||= "Needs Merge";
+        }
+
+        if ( defined ( $state->{entries}{$filename}{revision} ) and
+             not defined ( $meta->{revision} ) )
+        {
+            $status ||= "Locally Added";
+        }
+        if ( defined ( $wrev ) and defined ( $meta->{revision} ) and
+             $wrev eq "-$meta->{revision}" )
+        {
+            $status ||= "Locally Removed";
+        }
+        if ( defined ( $state->{entries}{$filename}{conflict} ) and
+             $state->{entries}{$filename}{conflict} =~ /^\+=/ )
+        {
+            $status ||= "Unresolved Conflict";
+        }
+        if ( 0 )
+        {
+            $status ||= "File had conflicts on merge";
+        }
 
         $status ||= "Unknown";
 
         my ($filepart) = filenamesplit($filename);
 
-        print "M ===================================================================\n";
+        print "M =======" . ( "=" x 60 ) . "\n";
         print "M File: $filepart\tStatus: $status\n";
         if ( defined($state->{entries}{$filename}{revision}) )
         {
-            print "M Working revision:\t" . $state->{entries}{$filename}{revision} . "\n";
+            print "M Working revision:\t" .
+                  $state->{entries}{$filename}{revision} . "\n";
         } else {
             print "M Working revision:\tNo entry for $filename\n";
         }
         if ( defined($meta->{revision}) )
         {
-            print "M Repository revision:\t1." . $meta->{revision} . "\t$state->{CVSROOT}/$state->{module}/$filename,v\n";
-            print "M Sticky Tag:\t\t(none)\n";
-            print "M Sticky Date:\t\t(none)\n";
-            print "M Sticky Options:\t\t(none)\n";
+            print "M Repository revision:\t" .
+                   $meta->{revision} .
+                   "\t$state->{CVSROOT}/$state->{module}/$filename,v\n";
+            my($tagOrDate)=$state->{entries}{$filename}{tag_or_date};
+            my($tag)=($tagOrDate=~m/^T(.+)$/);
+            if( !defined($tag) )
+            {
+                $tag="(none)";
+            }
+            print "M Sticky Tag:\t\t$tag\n";
+            my($date)=($tagOrDate=~m/^D(.+)$/);
+            if( !defined($date) )
+            {
+                $date="(none)";
+            }
+            print "M Sticky Date:\t\t$date\n";
+            my($options)=$state->{entries}{$filename}{options};
+            if( $options eq "" )
+            {
+                $options="(none)";
+            }
+            print "M Sticky Options:\t\t$options\n";
         } else {
             print "M Repository revision:\tNo revision control file\n";
         }
@@ -1651,16 +1727,17 @@ sub req_diff
         $revision1 = $state->{opt}{r};
     }
 
-    $revision1 =~ s/^1\.// if ( defined ( $revision1 ) );
-    $revision2 =~ s/^1\.// if ( defined ( $revision2 ) );
-
-    $log->debug("Diffing revisions " . ( defined($revision1) ? $revision1 : "[NULL]" ) . " and " . ( defined($revision2) ? $revision2 : "[NULL]" ) );
+    $log->debug("Diffing revisions " .
+                ( defined($revision1) ? $revision1 : "[NULL]" ) .
+                " and " . ( defined($revision2) ? $revision2 : "[NULL]" ) );
 
     # Grab a handle to the SQLite db and do any necessary updates
-    my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
+    my $updater;
+    $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
     $updater->update();
 
-    # if no files were specified, we need to work out what files we should be providing status on ...
+    # if no files were specified, we need to work out what files we should
+    # be providing status on ...
     argsfromdir($updater);
 
     # foreach file specified on the command line ...
@@ -1682,7 +1759,7 @@ sub req_diff
             $meta1 = $updater->getmeta($filename, $revision1);
             unless ( defined ( $meta1 ) and $meta1->{filehash} ne "deleted" )
             {
-                print "E File $filename at revision 1.$revision1 doesn't exist\n";
+                print "E File $filename at revision $revision1 doesn't exist\n";
                 next;
             }
             transmitfile($meta1->{filehash}, { targetfile => $file1 });
@@ -1703,7 +1780,7 @@ sub req_diff
 
             unless ( defined ( $meta2 ) and $meta2->{filehash} ne "deleted" )
             {
-                print "E File $filename at revision 1.$revision2 doesn't exist\n";
+                print "E File $filename at revision $revision2 doesn't exist\n";
                 next;
             }
 
@@ -1715,7 +1792,8 @@ sub req_diff
             $file2 = $state->{entries}{$filename}{modified_filename};
         }
 
-        # if we have been given -r, and we don't have a $file2 yet, lets get one
+        # if we have been given -r, and we don't have a $file2 yet, lets
+        # get one
         if ( defined ( $revision1 ) and not defined ( $file2 ) )
         {
             ( undef, $file2 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 );
@@ -1726,21 +1804,37 @@ sub req_diff
         # We need to have retrieved something useful
         next unless ( defined ( $meta1 ) );
 
-        # Files to date if the working copy and repo copy have the same revision, and the working copy is unmodified
-        next if ( not defined ( $meta2 ) and $wrev == $meta1->{revision}
-                  and
-                   ( ( $state->{entries}{$filename}{unchanged} and ( not defined ( $state->{entries}{$filename}{conflict} ) or $state->{entries}{$filename}{conflict} !~ /^\+=/ ) )
-                     or ( defined($state->{entries}{$filename}{modified_hash}) and $state->{entries}{$filename}{modified_hash} eq $meta1->{filehash} ) )
-                  );
+        # Files to date if the working copy and repo copy have the same
+        # revision, and the working copy is unmodified
+        if ( not defined ( $meta2 ) and $wrev eq $meta1->{revision} and
+             ( ( $state->{entries}{$filename}{unchanged} and
+                 ( not defined ( $state->{entries}{$filename}{conflict} ) or
+                   $state->{entries}{$filename}{conflict} !~ /^\+=/ ) ) or
+               ( defined($state->{entries}{$filename}{modified_hash}) and
+                 $state->{entries}{$filename}{modified_hash} eq
+                        $meta1->{filehash} ) ) )
+        {
+            next;
+        }
 
         # Apparently we only show diffs for locally modified files
-        next unless ( defined($meta2) or defined ( $state->{entries}{$filename}{modified_filename} ) );
+        unless ( defined($meta2) or
+                 defined ( $state->{entries}{$filename}{modified_filename} ) )
+        {
+            next;
+        }
 
         print "M Index: $filename\n";
-        print "M ===================================================================\n";
+        print "M =======" . ( "=" x 60 ) . "\n";
         print "M RCS file: $state->{CVSROOT}/$state->{module}/$filename,v\n";
-        print "M retrieving revision 1.$meta1->{revision}\n" if ( defined ( $meta1 ) );
-        print "M retrieving revision 1.$meta2->{revision}\n" if ( defined ( $meta2 ) );
+        if ( defined ( $meta1 ) )
+        {
+            print "M retrieving revision $meta1->{revision}\n"
+        }
+        if ( defined ( $meta2 ) )
+        {
+            print "M retrieving revision $meta2->{revision}\n"
+        }
         print "M diff ";
         foreach my $opt ( keys %{$state->{opt}} )
         {
@@ -1752,18 +1846,27 @@ sub req_diff
                 }
             } else {
                 print "-$opt ";
-                print "$state->{opt}{$opt} " if ( defined ( $state->{opt}{$opt} ) );
+                if ( defined ( $state->{opt}{$opt} ) )
+                {
+                    print "$state->{opt}{$opt} "
+                }
             }
         }
         print "$filename\n";
 
-        $log->info("Diffing $filename -r $meta1->{revision} -r " . ( $meta2->{revision} or "workingcopy" ));
+        $log->info("Diffing $filename -r $meta1->{revision} -r " .
+                   ( $meta2->{revision} or "workingcopy" ));
 
         ( $fh, $filediff ) = tempfile ( DIR => $TEMP_DIR );
 
         if ( exists $state->{opt}{u} )
         {
-            system("diff -u -L '$filename revision 1.$meta1->{revision}' -L '$filename " . ( defined($meta2->{revision}) ? "revision 1.$meta2->{revision}" : "working copy" ) . "' $file1 $file2 > $filediff");
+            system("diff -u -L '$filename revision $meta1->{revision}'" .
+                        " -L '$filename " .
+                        ( defined($meta2->{revision}) ?
+                                "revision $meta2->{revision}" :
+                                "working copy" ) .
+                        "' $file1 $file2 > $filediff" );
         } else {
             system("diff $file1 $file2 > $filediff");
         }
@@ -1787,22 +1890,19 @@ sub req_log
     $log->debug("req_log : " . ( defined($data) ? $data : "[NULL]" ));
     #$log->debug("log state : " . Dumper($state));
 
-    my ( $minrev, $maxrev );
-    if ( defined ( $state->{opt}{r} ) and $state->{opt}{r} =~ /([\d.]+)?(::?)([\d.]+)?/ )
+    my ( $revFilter );
+    if ( defined ( $state->{opt}{r} ) )
     {
-        my $control = $2;
-        $minrev = $1;
-        $maxrev = $3;
-        $minrev =~ s/^1\.// if ( defined ( $minrev ) );
-        $maxrev =~ s/^1\.// if ( defined ( $maxrev ) );
-        $minrev++ if ( defined($minrev) and $control eq "::" );
+        $revFilter = $state->{opt}{r};
     }
 
     # Grab a handle to the SQLite db and do any necessary updates
-    my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
+    my $updater;
+    $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
     $updater->update();
 
-    # if no files were specified, we need to work out what files we should be providing status on ...
+    # if no files were specified, we need to work out what files we
+    # should be providing status on ...
     argsfromdir($updater);
 
     # foreach file specified on the command line ...
@@ -1812,53 +1912,46 @@ sub req_log
 
         my $headmeta = $updater->getmeta($filename);
 
-        my $revisions = $updater->getlog($filename);
-        my $totalrevisions = scalar(@$revisions);
-
-        if ( defined ( $minrev ) )
-        {
-            $log->debug("Removing revisions less than $minrev");
-            while ( scalar(@$revisions) > 0 and $revisions->[-1]{revision} < $minrev )
-            {
-                pop @$revisions;
-            }
-        }
-        if ( defined ( $maxrev ) )
-        {
-            $log->debug("Removing revisions greater than $maxrev");
-            while ( scalar(@$revisions) > 0 and $revisions->[0]{revision} > $maxrev )
-            {
-                shift @$revisions;
-            }
-        }
+        my ($revisions,$totalrevisions) = $updater->getlog($filename,
+                                                           $revFilter);
 
         next unless ( scalar(@$revisions) );
 
         print "M \n";
         print "M RCS file: $state->{CVSROOT}/$state->{module}/$filename,v\n";
         print "M Working file: $filename\n";
-        print "M head: 1.$headmeta->{revision}\n";
+        print "M head: $headmeta->{revision}\n";
         print "M branch:\n";
         print "M locks: strict\n";
         print "M access list:\n";
         print "M symbolic names:\n";
         print "M keyword substitution: kv\n";
-        print "M total revisions: $totalrevisions;\tselected revisions: " . scalar(@$revisions) . "\n";
+        print "M total revisions: $totalrevisions;\tselected revisions: " .
+              scalar(@$revisions) . "\n";
         print "M description:\n";
 
         foreach my $revision ( @$revisions )
         {
             print "M ----------------------------\n";
-            print "M revision 1.$revision->{revision}\n";
+            print "M revision $revision->{revision}\n";
             # reformat the date for log output
-            $revision->{modified} = sprintf('%04d/%02d/%02d %s', $3, $DATE_LIST->{$2}, $1, $4 ) if ( $revision->{modified} =~ /(\d+)\s+(\w+)\s+(\d+)\s+(\S+)/ and defined($DATE_LIST->{$2}) );
+            if ( $revision->{modified} =~ /(\d+)\s+(\w+)\s+(\d+)\s+(\S+)/ and
+                 defined($DATE_LIST->{$2}) )
+            {
+                $revision->{modified} = sprintf('%04d/%02d/%02d %s',
+                                            $3, $DATE_LIST->{$2}, $1, $4 );
+            }
             $revision->{author} = cvs_author($revision->{author});
-            print "M date: $revision->{modified};  author: $revision->{author};  state: " . ( $revision->{filehash} eq "deleted" ? "dead" : "Exp" ) . ";  lines: +2 -3\n";
-            my $commitmessage = $updater->commitmessage($revision->{commithash});
+            print "M date: $revision->{modified};" .
+                  "  author: $revision->{author};  state: " .
+                  ( $revision->{filehash} eq "deleted" ? "dead" : "Exp" ) .
+                  ";  lines: +2 -3\n";
+            my $commitmessage;
+            $commitmessage = $updater->commitmessage($revision->{commithash});
             $commitmessage =~ s/^/M /mg;
             print $commitmessage . "\n";
         }
-        print "M =============================================================================\n";
+        print "M =======" . ( "=" x 70 ) . "\n";
     }
 
     print "ok\n";
@@ -1964,7 +2057,7 @@ sub req_annotate
                     $metadata->{$commithash}{author} = cvs_author($metadata->{$commithash}{author});
                     $metadata->{$commithash}{modified} = sprintf("%02d-%s-%02d", $1, $2, $3) if ( $metadata->{$commithash}{modified} =~ /^(\d+)\s(\w+)\s\d\d(\d\d)/ );
                 }
-                printf("M 1.%-5d      (%-8s %10s): %s\n",
+                printf("M %-7s      (%-8s %10s): %s\n",
                     $metadata->{$commithash}{revision},
                     $metadata->{$commithash}{author},
                     $metadata->{$commithash}{modified},
@@ -2085,7 +2178,7 @@ sub argsfromdir
     # push added files
     foreach my $file (keys %{$state->{entries}}) {
        if ( exists $state->{entries}{$file}{revision} &&
-               $state->{entries}{$file}{revision} == 0 )
+               $state->{entries}{$file}{revision} eq '0' )
        {
            push @gethead, { name => $file, filehash => 'added' };
        }
@@ -2129,16 +2222,15 @@ sub statecleanup
     $state->{entries} = {};
 }
 
+# Return working directory CVS revision "1.X" out
+# of the the working directory "entries" state, for the given filename.
+# This is prefixed with a dash if the file is scheduled for removal
+# when it is committed.
 sub revparse
 {
     my $filename = shift;
 
-    return undef unless ( defined ( $state->{entries}{$filename}{revision} ) );
-
-    return $1 if ( $state->{entries}{$filename}{revision} =~ /^1\.(\d+)/ );
-    return -$1 if ( $state->{entries}{$filename}{revision} =~ /^-1\.(\d+)/ );
-
-    return undef;
+    return $state->{entries}{$filename}{revision};
 }
 
 # This method takes a file hash and does a CVS "file transfer".  Its
@@ -2444,42 +2536,14 @@ sub kopts_from_path
         }
         elsif( ($cfg->{gitcvs}{allbinary} =~ /^\s*guess\s*$/i) )
         {
-            if( $srcType eq "sha1Or-k" &&
-                !defined($name) )
+            if( is_binary($srcType,$name) )
             {
-                my ($ret)=$state->{entries}{$path}{options};
-                if( !defined($ret) )
-                {
-                    $ret=$state->{opt}{k};
-                    if(defined($ret))
-                    {
-                        $ret="-k$ret";
-                    }
-                    else
-                    {
-                        $ret="";
-                    }
-                }
-                if( ! ($ret=~/^(|-kb|-kkv|-kkvl|-kk|-ko|-kv)$/) )
-                {
-                    print "E Bad -k option\n";
-                    $log->warn("Bad -k option: $ret");
-                    die "Error: Bad -k option: $ret\n";
-                }
-
-                return $ret;
+                $log->debug("... as binary");
+                return "-kb";
             }
             else
             {
-                if( is_binary($srcType,$name) )
-                {
-                    $log->debug("... as binary");
-                    return "-kb";
-                }
-                else
-                {
-                    $log->debug("... as text");
-                }
+                $log->debug("... as text");
             }
         }
     }
@@ -2586,7 +2650,7 @@ sub open_blob_or_die
             die "Unable to open file $name: $!\n";
         }
     }
-    elsif( $srcType eq "sha1" || $srcType eq "sha1Or-k" )
+    elsif( $srcType eq "sha1" )
     {
         unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{40}$/ )
         {
@@ -2929,6 +2993,16 @@ sub new
     }
 
     # Construct the revision table if required
+    # The revision table stores an entry for each file, each time that file
+    # changes.
+    #   numberOfRecords = O( numCommits * averageNumChangedFilesPerCommit )
+    # This is not sufficient to support "-r {commithash}" for any
+    # files except files that were modified by that commit (also,
+    # some places in the code ignore/effectively strip out -r in
+    # some cases, before it gets passed to getmeta()).
+    # The "filehash" field typically has a git blob hash, but can also
+    # be set to "dead" to indicate that the given version of the file
+    # should not exist in the sandbox.
     unless ( $self->{tables}{$self->tablename("revision")} )
     {
         my $tablename = $self->tablename("revision");
@@ -2956,6 +3030,15 @@ sub new
     }
 
     # Construct the head table if required
+    # The head table (along with the "last_commit" entry in the property
+    # table) is the persisted working state of the "sub update" subroutine.
+    # All of it's data is read entirely first, and completely recreated
+    # last, every time "sub update" runs.
+    # This is also used by "sub getmeta" when it is asked for the latest
+    # version of a file (as opposed to some specific version).
+    # Another way of thinking about it is as a single slice out of
+    # "revisions", giving just the most recent revision information for
+    # each file.
     unless ( $self->{tables}{$self->tablename("head")} )
     {
         my $tablename = $self->tablename("head");
@@ -2978,6 +3061,7 @@ sub new
     }
 
     # Construct the properties table if required
+    #  - "last_commit" - Used by "sub update".
     unless ( $self->{tables}{$self->tablename("properties")} )
     {
         my $tablename = $self->tablename("properties");
@@ -2990,6 +3074,11 @@ sub new
     }
 
     # Construct the commitmsgs table if required
+    # The commitmsgs table is only used for merge commits, since
+    # "sub update" will only keep one branch of parents.  Shortlogs
+    # for ignored commits (i.e. not on the chosen branch) will be used
+    # to construct a replacement "collapsed" merge commit message,
+    # which will be stored in this table.  See also "sub commitmessage".
     unless ( $self->{tables}{$self->tablename("commitmsgs")} )
     {
         my $tablename = $self->tablename("commitmsgs");
@@ -3021,6 +3110,14 @@ sub tablename
 
 =head2 update
 
+Bring the database up to date with the latest changes from
+the git repository.
+
+Internal working state is read out of the "head" table and the
+"last_commit" property, then it updates "revisions" based on that, and
+finally it writes the new internal state back to the "head" table
+so it can be used as a starting point the next time update is called.
+
 =cut
 sub update
 {
@@ -3116,7 +3213,7 @@ sub update
     my $commitcount = 0;
 
     # Load the head table into $head (for cached lookups during the update process)
-    foreach my $file ( @{$self->gethead()} )
+    foreach my $file ( @{$self->gethead(1)} )
     {
         $head->{$file->{name}} = $file;
     }
@@ -3134,17 +3231,18 @@ sub update
                 next;
             } elsif (@{$commit->{parents}} > 1) {
                 # it is a merge commit, for each parent that is
-                # not $lastpicked, see if we can get a log
+                # not $lastpicked (not given a CVS revision number),
+                # see if we can get a log
                 # from the merge-base to that parent to put it
                 # in the message as a merge summary.
                 my @parents = @{$commit->{parents}};
                 foreach my $parent (@parents) {
-                    # git-merge-base can potentially (but rarely) throw
-                    # several candidate merge bases. let's assume
-                    # that the first one is the best one.
                     if ($parent eq $lastpicked) {
                         next;
                     }
+                    # git-merge-base can potentially (but rarely) throw
+                    # several candidate merge bases. let's assume
+                    # that the first one is the best one.
                    my $base = eval {
                            safe_pipe_capture('git', 'merge-base',
                                                 $lastpicked, $parent);
@@ -3426,19 +3524,6 @@ sub insert_head
     $insert_head->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode);
 }
 
-sub _headrev
-{
-    my $self = shift;
-    my $filename = shift;
-    my $tablename = $self->tablename("head");
-
-    my $db_query = $self->{dbh}->prepare_cached("SELECT filehash, revision, mode FROM $tablename WHERE name=?",{},1);
-    $db_query->execute($filename);
-    my ( $hash, $revision, $mode ) = $db_query->fetchrow_array;
-
-    return ( $hash, $revision, $mode );
-}
-
 sub _get_prop
 {
     my $self = shift;
@@ -3478,6 +3563,7 @@ sub _set_prop
 sub gethead
 {
     my $self = shift;
+    my $intRev = shift;
     my $tablename = $self->tablename("head");
 
     return $self->{gethead_cache} if ( defined ( $self->{gethead_cache} ) );
@@ -3488,6 +3574,10 @@ sub gethead
     my $tree = [];
     while ( my $file = $db_query->fetchrow_hashref )
     {
+        if(!$intRev)
+        {
+            $file->{revision} = "1.$file->{revision}"
+        }
         push @$tree, $file;
     }
 
@@ -3498,24 +3588,57 @@ sub gethead
 
 =head2 getlog
 
+See also gethistorydense().
+
 =cut
 
 sub getlog
 {
     my $self = shift;
     my $filename = shift;
+    my $revFilter = shift;
+
     my $tablename = $self->tablename("revision");
 
+    # Filters:
+    # TODO: date, state, or by specific logins filters?
+    # TODO: Handle comma-separated list of revFilter items, each item
+    #   can be a range [only case currently handled] or individual
+    #   rev or branch or "branch.".
+    # TODO: Adjust $db_query WHERE clause based on revFilter, instead of
+    #   manually filtering the results of the query?
+    my ( $minrev, $maxrev );
+    if( defined($revFilter) and
+        $state->{opt}{r} =~ /^(1.(\d+))?(::?)(1.(\d.+))?$/ )
+    {
+        my $control = $3;
+        $minrev = $2;
+        $maxrev = $5;
+        $minrev++ if ( defined($minrev) and $control eq "::" );
+    }
+
     my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, author, mode, revision, modified, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1);
     $db_query->execute($filename);
 
+    my $totalRevs=0;
     my $tree = [];
     while ( my $file = $db_query->fetchrow_hashref )
     {
+        $totalRevs++;
+        if( defined($minrev) and $file->{revision} < $minrev )
+        {
+            next;
+        }
+        if( defined($maxrev) and $file->{revision} > $maxrev )
+        {
+            next;
+        }
+
+        $file->{revision} = "1." . $file->{revision};
         push @$tree, $file;
     }
 
-    return $tree;
+    return ($tree,$totalRevs);
 }
 
 =head2 getmeta
@@ -3534,10 +3657,11 @@ sub getmeta
     my $tablename_head = $self->tablename("head");
 
     my $db_query;
-    if ( defined($revision) and $revision =~ /^\d+$/ )
+    if ( defined($revision) and $revision =~ /^1\.(\d+)$/ )
     {
+        my ($intRev) = $1;
         $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND revision=?",{},1);
-        $db_query->execute($filename, $revision);
+        $db_query->execute($filename, $intRev);
     }
     elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ )
     {
@@ -3548,7 +3672,12 @@ sub getmeta
         $db_query->execute($filename);
     }
 
-    return $db_query->fetchrow_hashref;
+    my $meta = $db_query->fetchrow_hashref;
+    if($meta)
+    {
+        $meta->{revision} = "1.$meta->{revision}";
+    }
+    return $meta;
 }
 
 =head2 commitmessage
@@ -3583,25 +3712,6 @@ sub commitmessage
     return $message;
 }
 
-=head2 gethistory
-
-This function takes a filename (with path) argument and returns an arrayofarrays
-containing revision,filehash,commithash ordered by revision descending
-
-=cut
-sub gethistory
-{
-    my $self = shift;
-    my $filename = shift;
-    my $tablename = $self->tablename("revision");
-
-    my $db_query;
-    $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1);
-    $db_query->execute($filename);
-
-    return $db_query->fetchall_arrayref;
-}
-
 =head2 gethistorydense
 
 This function takes a filename (with path) argument and returns an arrayofarrays
@@ -3611,6 +3721,8 @@ This version of gethistory skips deleted entries -- so it is useful for annotate
 The 'dense' part is a reference to a '--dense' option available for git-rev-list
 and other git tools that depend on it.
 
+See also getlog().
+
 =cut
 sub gethistorydense
 {
@@ -3622,7 +3734,15 @@ sub gethistorydense
     $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? AND filehash!='deleted' ORDER BY revision DESC",{},1);
     $db_query->execute($filename);
 
-    return $db_query->fetchall_arrayref;
+    my $result = $db_query->fetchall_arrayref;
+
+    my $i;
+    for($i=0 ; $i<scalar(@$result) ; $i++)
+    {
+        $result->[$i][0]="1." . $result->[$i][0];
+    }
+
+    return $result;
 }
 
 =head2 in_array()
index 178e453..5314249 100755 (executable)
@@ -64,37 +64,19 @@ EOF
 
 eval "$functions"
 
-# When piped a commit, output a script to set the ident of either
-# "author" or "committer
+finish_ident() {
+       # Ensure non-empty id name.
+       echo "case \"\$GIT_$1_NAME\" in \"\") GIT_$1_NAME=\"\${GIT_$1_EMAIL%%@*}\" && export GIT_$1_NAME;; esac"
+       # And make sure everything is exported.
+       echo "export GIT_$1_NAME"
+       echo "export GIT_$1_EMAIL"
+       echo "export GIT_$1_DATE"
+}
 
 set_ident () {
-       lid="$(echo "$1" | tr "[A-Z]" "[a-z]")"
-       uid="$(echo "$1" | tr "[a-z]" "[A-Z]")"
-       pick_id_script='
-               /^'$lid' /{
-                       s/'\''/'\''\\'\'\''/g
-                       h
-                       s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
-                       s/'\''/'\''\'\'\''/g
-                       s/.*/GIT_'$uid'_NAME='\''&'\''; export GIT_'$uid'_NAME/p
-
-                       g
-                       s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
-                       s/'\''/'\''\'\'\''/g
-                       s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p
-
-                       g
-                       s/^'$lid' [^<]* <[^>]*> \(.*\)$/@\1/
-                       s/'\''/'\''\'\'\''/g
-                       s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p
-
-                       q
-               }
-       '
-
-       LANG=C LC_ALL=C sed -ne "$pick_id_script"
-       # Ensure non-empty id name.
-       echo "case \"\$GIT_${uid}_NAME\" in \"\") GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\" && export GIT_${uid}_NAME;; esac"
+       parse_ident_from_commit author AUTHOR committer COMMITTER
+       finish_ident AUTHOR
+       finish_ident COMMITTER
 }
 
 USAGE="[--env-filter <command>] [--tree-filter <command>]
@@ -320,10 +302,8 @@ while read commit parents; do
        git cat-file commit "$commit" >../commit ||
                die "Cannot read commit $commit"
 
-       eval "$(set_ident AUTHOR <../commit)" ||
-               die "setting author failed for commit $commit"
-       eval "$(set_ident COMMITTER <../commit)" ||
-               die "setting committer failed for commit $commit"
+       eval "$(set_ident <../commit)" ||
+               die "setting author/committer failed for commit $commit"
        eval "$filter_env" < /dev/null ||
                die "env filter failed: $filter_env"
 
index 882b1bb..0682e61 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -12,6 +12,21 @@ import optparse, sys, os, marshal, subprocess, shelve
 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
@@ -129,17 +144,40 @@ def p4_has_command(cmd):
     p.communicate()
     return p.returncode == 0
 
+def p4_has_move_command():
+    """See if the move command exists, that it supports -k, and that
+       it has not been administratively disabled.  The arguments
+       must be correct, but the filenames do not have to exist.  Use
+       ones with wildcards so even if they exist, it will fail."""
+
+    if not p4_has_command("move"):
+        return False
+    cmd = p4_build_cmd(["move", "-k", "@from", "@to"])
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    (out, err) = p.communicate()
+    # return code will be 1 in either case
+    if err.find("Invalid option") >= 0:
+        return False
+    if err.find("disabled") >= 0:
+        return False
+    # assume it failed because @... was invalid changelist
+    return True
+
 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)])
@@ -169,6 +207,29 @@ def p4_reopen(type, f):
 def p4_move(src, dest):
     p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
 
+def p4_describe(change):
+    """Make sure it returns a valid result by checking for
+       the presence of field "time".  Return a dict of the
+       results."""
+
+    ds = p4CmdList(["describe", "-s", str(change)])
+    if len(ds) != 1:
+        die("p4 describe -s %d did not return 1 result: %s" % (change, str(ds)))
+
+    d = ds[0]
+
+    if "p4ExitCode" in d:
+        die("p4 describe -s %d exited with %d: %s" % (change, d["p4ExitCode"],
+                                                      str(d)))
+    if "code" in d:
+        if d["code"] == "error":
+            die("p4 describe -s %d returned error code: %s" % (change, str(d)))
+
+    if "time" not in d:
+        die("p4 describe -s %d returned no \"time\": %s" % (change, str(d)))
+
+    return d
+
 #
 # Canonicalize the p4 type and return a tuple of the
 # base type, plus any modifiers.  See "p4 help filetypes"
@@ -227,7 +288,7 @@ def p4_keywords_regexp_for_type(base, type_mods):
         pattern = r"""
             \$              # Starts with a dollar, followed by...
             (%s)            # one of the keywords, followed by...
-            (:[^$]+)?       # possibly an old expansion, followed by...
+            (:[^$\n]+)?     # possibly an old expansion, followed by...
             \$              # another dollar
             """ % kwords
         return pattern
@@ -700,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):
@@ -871,7 +933,7 @@ class P4Submit(Command, P4UserMap):
         self.conflict_behavior = None
         self.isWindows = (platform.system() == "Windows")
         self.exportLabels = False
-        self.p4HasMoveCommand = p4_has_command("move")
+        self.p4HasMoveCommand = p4_has_move_command()
 
     def check(self):
         if len(p4CmdList("opened ...")) > 0:
@@ -2097,6 +2159,29 @@ class P4Sync(Command, P4UserMap):
     # handle another chunk of streaming data
     def streamP4FilesCb(self, marshalled):
 
+        # catch p4 errors and complain
+        err = None
+        if "code" in marshalled:
+            if marshalled["code"] == "error":
+                if "data" in marshalled:
+                    err = marshalled["data"].rstrip()
+        if err:
+            f = None
+            if self.stream_have_file_info:
+                if "depotFile" in self.stream_file:
+                    f = self.stream_file["depotFile"]
+            # force a failure in fast-import, else an empty
+            # commit will be made
+            self.gitStream.write("\n")
+            self.gitStream.write("die-now\n")
+            self.gitStream.close()
+            # ignore errors, but make sure it exits first
+            self.importProcess.wait()
+            if f:
+                die("Error from p4 print for %s: %s" % (f, err))
+            else:
+                die("Error from p4 print: %s" % err)
+
         if marshalled.has_key('depotFile') and self.stream_have_file_info:
             # start of a new file - output the old one first
             self.streamOneP4File(self.stream_file, self.stream_contents)
@@ -2341,7 +2426,7 @@ class P4Sync(Command, P4UserMap):
                     try:
                         tmwhen = time.strptime(labelDetails['Update'], "%Y/%m/%d %H:%M:%S")
                     except ValueError:
-                        print "Could not convert label time %s" % labelDetail['Update']
+                        print "Could not convert label time %s" % labelDetails['Update']
                         tmwhen = 1
 
                     when = int(time.mktime(tmwhen))
@@ -2543,7 +2628,7 @@ class P4Sync(Command, P4UserMap):
     def importChanges(self, changes):
         cnt = 1
         for change in changes:
-            description = p4Cmd(["describe", str(change)])
+            description = p4_describe(change)
             self.updateOptionDict(description)
 
             if not self.silent:
@@ -2667,14 +2752,8 @@ class P4Sync(Command, P4UserMap):
 
         # Use time from top-most change so that all git p4 clones of
         # the same p4 repo have the same commit SHA1s.
-        res = p4CmdList("describe -s %d" % newestRevision)
-        newestTime = None
-        for r in res:
-            if r.has_key('time'):
-                newestTime = int(r['time'])
-        if newestTime is None:
-            die("\"describe -s\" on newest change %d did not give a time")
-        details["time"] = newestTime
+        res = p4_describe(newestRevision)
+        details["time"] = res["time"]
 
         self.updateOptionDict(details)
         try:
@@ -2864,12 +2943,13 @@ class P4Sync(Command, P4UserMap):
 
         self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
 
-        importProcess = subprocess.Popen(["git", "fast-import"],
-                                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
-                                         stderr=subprocess.PIPE);
-        self.gitOutput = importProcess.stdout
-        self.gitStream = importProcess.stdin
-        self.gitError = importProcess.stderr
+        self.importProcess = subprocess.Popen(["git", "fast-import"],
+                                              stdin=subprocess.PIPE,
+                                              stdout=subprocess.PIPE,
+                                              stderr=subprocess.PIPE);
+        self.gitOutput = self.importProcess.stdout
+        self.gitStream = self.importProcess.stdin
+        self.gitError = self.importProcess.stderr
 
         if revision:
             self.importHeadRevision(revision)
@@ -2929,7 +3009,7 @@ class P4Sync(Command, P4UserMap):
             self.importP4Labels(self.gitStream, missingP4Labels)
 
         self.gitStream.close()
-        if importProcess.wait() != 0:
+        if self.importProcess.wait() != 0:
             die("fast-import failed: %s" % self.gitError.read())
         self.gitOutput.close()
         self.gitError.close()
@@ -3043,7 +3123,9 @@ class P4Clone(P4Sync):
         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
@@ -3128,7 +3210,6 @@ def main():
         printUsage(commands.keys())
         sys.exit(2)
 
-    cmd = ""
     cmdName = sys.argv[1]
     try:
         klass = commands[cmdName]
index 484b2e6..0e87e09 100644 (file)
@@ -80,7 +80,7 @@ See git-${cmd}(1) for details
 
 If you wish to set tracking information for this branch you can do so with:
 
-    git branch --set-upstream ${branch_name#refs/heads/} $remote/<branch>
+    git branch --set-upstream-to=$remote/<branch> ${branch_name#refs/heads/}
 "
        fi
        exit 1
index 2a10047..266e682 100755 (executable)
@@ -200,6 +200,7 @@ test true = "$rebase" && {
                require_clean_work_tree "pull with rebase" "Please commit or stash them."
        fi
        oldremoteref= &&
+       test -n "$curr_branch" &&
        . git-parse-remote &&
        remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
        oldremoteref="$(git rev-parse -q --verify "$remoteref")" &&
index 44901d5..8ed7fcc 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 aea66a0..be809e5 100755 (executable)
@@ -56,6 +56,7 @@ git send-email [options] <file | directory | rev-list options >
     --in-reply-to           <str>  * Email "In-Reply-To:"
     --annotate                     * Review each patch that will be sent in an editor.
     --compose                      * Open an editor for introduction.
+    --compose-encoding      <str>  * Encoding to assume for introduction.
     --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
 
   Sending:
@@ -198,6 +199,7 @@ my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
 my ($validate, $confirm);
 my (@suppress_cc);
 my ($auto_8bit_encoding);
+my ($compose_encoding);
 
 my ($debug_net_smtp) = 0;              # Net::SMTP, see send_message()
 
@@ -231,6 +233,7 @@ my %config_settings = (
     "confirm"   => \$confirm,
     "from" => \$sender,
     "assume8bitencoding" => \$auto_8bit_encoding,
+    "composeencoding" => \$compose_encoding,
 );
 
 my %config_path_settings = (
@@ -315,6 +318,7 @@ my $rc = GetOptions("h" => \$help,
                    "validate!" => \$validate,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
+                   "compose-encoding=s" => \$compose_encoding,
                    "force" => \$force,
         );
 
@@ -632,6 +636,9 @@ EOT
        my $need_8bit_cte = file_has_nonascii($compose_filename);
        my $in_body = 0;
        my $summary_empty = 1;
+       if (!defined $compose_encoding) {
+               $compose_encoding = "UTF-8";
+       }
        while(<$c>) {
                next if m/^GIT:/;
                if ($in_body) {
@@ -641,7 +648,7 @@ EOT
                        if ($need_8bit_cte) {
                                print $c2 "MIME-Version: 1.0\n",
                                         "Content-Type: text/plain; ",
-                                          "charset=UTF-8\n",
+                                          "charset=$compose_encoding\n",
                                         "Content-Transfer-Encoding: 8bit\n";
                        }
                } elsif (/^MIME-Version:/i) {
@@ -650,9 +657,7 @@ EOT
                        $initial_subject = $1;
                        my $subject = $initial_subject;
                        $_ = "Subject: " .
-                               ($subject =~ /[^[:ascii:]]/ ?
-                                quote_rfc2047($subject) :
-                                $subject) .
+                               quote_subject($subject, $compose_encoding) .
                                "\n";
                } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
                        $initial_reply_to = $1;
@@ -748,16 +753,11 @@ if (!$force) {
        }
 }
 
-my $prompting = 0;
 if (!defined $sender) {
        $sender = $repoauthor || $repocommitter || '';
-       $sender = ask("Who should the emails appear to be from? [$sender] ",
-                     default => $sender,
-                     valid_re => qr/\@.*\./, confirm_only => 1);
-       print "Emails will be sent from: ", $sender, "\n";
-       $prompting++;
 }
 
+my $prompting = 0;
 if (!@initial_to && !defined $to_cmd) {
        my $to = ask("Who should the emails be sent to (if any)? ",
                     default => "",
@@ -781,9 +781,11 @@ sub expand_one_alias {
 }
 
 @initial_to = expand_aliases(@initial_to);
-@initial_to = (map { sanitize_address($_) } @initial_to);
+@initial_to = validate_address_list(sanitize_address_list(@initial_to));
 @initial_cc = expand_aliases(@initial_cc);
+@initial_cc = validate_address_list(sanitize_address_list(@initial_cc));
 @bcclist = expand_aliases(@bcclist);
+@bcclist = validate_address_list(sanitize_address_list(@bcclist));
 
 if ($thread && !defined $initial_reply_to && $prompting) {
        $initial_reply_to = ask(
@@ -826,12 +828,45 @@ sub extract_valid_address {
        $address =~ s/^\s*<(.*)>\s*$/$1/;
        if ($have_email_valid) {
                return scalar Email::Valid->address($address);
-       } else {
-               # less robust/correct than the monster regexp in Email::Valid,
-               # but still does a 99% job, and one less dependency
-               $address =~ /($local_part_regexp\@$domain_regexp)/;
-               return $1;
        }
+
+       # less robust/correct than the monster regexp in Email::Valid,
+       # but still does a 99% job, and one less dependency
+       return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
+       return undef;
+}
+
+sub extract_valid_address_or_die {
+       my $address = shift;
+       $address = extract_valid_address($address);
+       die "error: unable to extract a valid address from: $address\n"
+               if !$address;
+       return $address;
+}
+
+sub validate_address {
+       my $address = shift;
+       while (!extract_valid_address($address)) {
+               print STDERR "error: unable to extract a valid address from: $address\n";
+               $_ = ask("What to do with this address? ([q]uit|[d]rop|[e]dit): ",
+                       valid_re => qr/^(?:quit|q|drop|d|edit|e)/i,
+                       default => 'q');
+               if (/^d/i) {
+                       return undef;
+               } elsif (/^q/i) {
+                       cleanup_compose_files();
+                       exit(0);
+               }
+               $address = ask("Who should the email be sent to (if any)? ",
+                       default => "",
+                       valid_re => qr/\@.*\./, confirm_only => 1);
+       }
+       return $address;
+}
+
+sub validate_address_list {
+       return (grep { defined $_ }
+               map { validate_address($_) } @_);
 }
 
 # Usually don't need to change anything below here.
@@ -900,9 +935,29 @@ sub is_rfc2047_quoted {
        $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
 }
 
+sub subject_needs_rfc2047_quoting {
+       my $s = shift;
+
+       return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
+}
+
+sub quote_subject {
+       local $subject = shift;
+       my $encoding = shift || 'UTF-8';
+
+       if (subject_needs_rfc2047_quoting($subject)) {
+               return quote_rfc2047($subject, $encoding);
+       }
+       return $subject;
+}
+
 # use the simplest quoting being able to handle the recipient
 sub sanitize_address {
        my ($recipient) = @_;
+
+       # remove garbage after email address
+       $recipient =~ s/(.*>).*$/$1/;
+
        my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
 
        if (not $recipient_name) {
@@ -930,6 +985,10 @@ sub sanitize_address {
 
 }
 
+sub sanitize_address_list {
+       return (map { sanitize_address($_) } @_);
+}
+
 # Returns the local Fully Qualified Domain Name (FQDN) if available.
 #
 # Tightly configured MTAa require that a caller sends a real DNS
@@ -992,14 +1051,13 @@ sub maildomain {
 
 sub send_message {
        my @recipients = unique_email_list(@to);
-       @cc = (grep { my $cc = extract_valid_address($_);
+       @cc = (grep { my $cc = extract_valid_address_or_die($_);
                      not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
                    }
-              map { sanitize_address($_) }
               @cc);
        my $to = join (",\n\t", @recipients);
        @recipients = unique_email_list(@recipients,@cc,@bcclist);
-       @recipients = (map { extract_valid_address($_) } @recipients);
+       @recipients = (map { extract_valid_address_or_die($_) } @recipients);
        my $date = format_2822_time($time++);
        my $gitversion = '@@GIT_VERSION@@';
        if ($gitversion =~ m/..GIT_VERSION../) {
@@ -1227,10 +1285,10 @@ foreach my $t (@files) {
                }
 
                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;
@@ -1238,14 +1296,14 @@ foreach my $t (@files) {
                                        $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, sanitize_address($addr);
+                                       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'});
@@ -1267,7 +1325,7 @@ foreach my $t (@files) {
                        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, $_;
                        }
 
@@ -1321,7 +1379,7 @@ foreach my $t (@files) {
        }
 
        if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) {
-               $subject = quote_rfc2047($subject, $auto_8bit_encoding);
+               $subject = quote_subject($subject, $auto_8bit_encoding);
        }
 
        if (defined $author and $author ne $sender) {
@@ -1351,6 +1409,9 @@ foreach my $t (@files) {
                ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
        $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
 
+       @to = validate_address_list(sanitize_address_list(@to));
+       @cc = validate_address_list(sanitize_address_list(@cc));
+
        @to = (@initial_to, @to);
        @cc = (@initial_cc, @cc);
 
@@ -1406,14 +1467,10 @@ sub unique_email_list {
        my @emails;
 
        foreach my $entry (@_) {
-               if (my $clean = extract_valid_address($entry)) {
-                       $seen{$clean} ||= 0;
-                       next if $seen{$clean}++;
-                       push @emails, $entry;
-               } else {
-                       print STDERR "W: unable to extract a valid address",
-                                       " from: $entry\n";
-               }
+               my $clean = extract_valid_address_or_die($entry);
+               $seen{$clean} ||= 0;
+               next if $seen{$clean}++;
+               push @emails, $entry;
        }
        return @emails;
 }
index ee0e0bc..795edd2 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
@@ -191,28 +194,52 @@ require_clean_work_tree () {
        fi
 }
 
+# Generate a sed script to parse identities from a commit.
+#
+# Reads the commit from stdin, which should be in raw format (e.g., from
+# cat-file or "--pretty=raw").
+#
+# The first argument specifies the ident line to parse (e.g., "author"), and
+# the second specifies the environment variable to put it in (e.g., "AUTHOR"
+# for "GIT_AUTHOR_*"). Multiple pairs can be given to parse author and
+# committer.
+pick_ident_script () {
+       while test $# -gt 0
+       do
+               lid=$1; shift
+               uid=$1; shift
+               printf '%s' "
+               /^$lid /{
+                       s/'/'\\\\''/g
+                       h
+                       s/^$lid "'\([^<]*\) <[^>]*> .*$/\1/'"
+                       s/.*/GIT_${uid}_NAME='&'/p
+
+                       g
+                       s/^$lid "'[^<]* <\([^>]*\)> .*$/\1/'"
+                       s/.*/GIT_${uid}_EMAIL='&'/p
+
+                       g
+                       s/^$lid "'[^<]* <[^>]*> \(.*\)$/@\1/'"
+                       s/.*/GIT_${uid}_DATE='&'/p
+               }
+               "
+       done
+       echo '/^$/q'
+}
+
+# Create a pick-script as above and feed it to sed. Stdout is suitable for
+# feeding to eval.
+parse_ident_from_commit () {
+       LANG=C LC_ALL=C sed -ne "$(pick_ident_script "$@")"
+}
+
+# Parse the author from a commit given as an argument. Stdout is suitable for
+# feeding to eval to set the usual GIT_* ident variables.
 get_author_ident_from_commit () {
-       pick_author_script='
-       /^author /{
-               s/'\''/'\''\\'\'\''/g
-               h
-               s/^author \([^<]*\) <[^>]*> .*$/\1/
-               s/.*/GIT_AUTHOR_NAME='\''&'\''/p
-
-               g
-               s/^author [^<]* <\([^>]*\)> .*$/\1/
-               s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
-
-               g
-               s/^author [^<]* <[^>]*> \(.*\)$/@\1/
-               s/.*/GIT_AUTHOR_DATE='\''&'\''/p
-
-               q
-       }
-       '
        encoding=$(git config i18n.commitencoding || echo UTF-8)
        git show -s --pretty=raw --encoding="$encoding" "$1" -- |
-       LANG=C LC_ALL=C sed -ne "$pick_author_script"
+       parse_ident_from_commit author AUTHOR
 }
 
 # Clear repo-local GIT_* environment variables. Useful when switching to
index ab6b110..2365149 100755 (executable)
@@ -5,13 +5,13 @@
 # Copyright (c) 2007 Lars Hjemli
 
 dashless=$(basename "$0" | sed -e 's/-/ /')
-USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
+USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] init [--] [<path>...]
    or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
    or: $dashless [--quiet] foreach [--recursive] <command>
-   or: $dashless [--quiet] sync [--] [<path>...]"
+   or: $dashless [--quiet] sync [--recursive] [--] [<path>...]"
 OPTIONS_SPEC=
 . git-sh-setup
 . git-sh-i18n
@@ -29,6 +29,7 @@ files=
 nofetch=
 update=
 prefix=
+custom_name=
 
 # The function takes at most 2 arguments. The first argument is the
 # URL that navigates to the submodule origin repo. When relative, this URL
@@ -179,8 +180,9 @@ module_name()
 module_clone()
 {
        sm_path=$1
-       url=$2
-       reference="$3"
+       name=$2
+       url=$3
+       reference="$4"
        quiet=
        if test -n "$GIT_QUIET"
        then
@@ -189,8 +191,6 @@ module_clone()
 
        gitdir=
        gitdir_base=
-       name=$(module_name "$sm_path" 2>/dev/null)
-       test -n "$name" || name="$sm_path"
        base_name=$(dirname "$name")
 
        gitdir=$(git rev-parse --git-dir)
@@ -270,6 +270,10 @@ cmd_add()
                        ;;
                --reference=*)
                        reference="$1"
+                       ;;
+               --name)
+                       case "$2" in '') usage ;; esac
+                       custom_name=$2
                        shift
                        ;;
                --)
@@ -336,6 +340,13 @@ Use -f if you really want to add it." >&2
                exit 1
        fi
 
+       if test -n "$custom_name"
+       then
+               sm_name="$custom_name"
+       else
+               sm_name="$sm_path"
+       fi
+
        # perhaps the path exists and is already a git repo, else clone it
        if test -e "$sm_path"
        then
@@ -347,8 +358,21 @@ Use -f if you really want to add it." >&2
                fi
 
        else
-
-               module_clone "$sm_path" "$realrepo" "$reference" || exit
+               if test -d ".git/modules/$sm_name"
+               then
+                       if test -z "$force"
+                       then
+                               echo >&2 "$(eval_gettext "A git directory for '\$sm_name' is found locally with remote(s):")"
+                               GIT_DIR=".git/modules/$sm_name" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,"  ", -e s,' (fetch)',, >&2
+                               echo >&2 "$(eval_gettext "If you want to reuse this local git directory instead of cloning again from")"
+                               echo >&2 "  $realrepo"
+                               echo >&2 "$(eval_gettext "use the '--force' option. If the local git directory is not the correct repo")"
+                               die "$(eval_gettext "or you are unsure what this means choose another name with the '--name' option.")"
+                       else
+                               echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
+                       fi
+               fi
+               module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" || exit
                (
                        clear_local_git_env
                        cd "$sm_path" &&
@@ -359,13 +383,13 @@ Use -f if you really want to add it." >&2
                        esac
                ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
        fi
-       git config submodule."$sm_path".url "$realrepo"
+       git config submodule."$sm_name".url "$realrepo"
 
        git add $force "$sm_path" ||
        die "$(eval_gettext "Failed to add submodule '\$sm_path'")"
 
-       git config -f .gitmodules submodule."$sm_path".path "$sm_path" &&
-       git config -f .gitmodules submodule."$sm_path".url "$repo" &&
+       git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
+       git config -f .gitmodules submodule."$sm_name".url "$repo" &&
        git add --force .gitmodules ||
        die "$(eval_gettext "Failed to register submodule '\$sm_path'")"
 }
@@ -594,7 +618,7 @@ Maybe you want to use 'update --init'?")"
 
                if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
                then
-                       module_clone "$sm_path" "$url" "$reference"|| exit
+                       module_clone "$sm_path" "$name" "$url" "$reference" || exit
                        cloned_modules="$cloned_modules;$name"
                        subsha1=
                else
@@ -926,7 +950,6 @@ cmd_summary() {
 cmd_status()
 {
        # parse $args after "submodule ... status".
-       orig_flags=
        while test $# -ne 0
        do
                case "$1" in
@@ -950,7 +973,6 @@ cmd_status()
                        break
                        ;;
                esac
-               orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
                shift
        done
 
@@ -990,7 +1012,7 @@ cmd_status()
                                prefix="$displaypath/"
                                clear_local_git_env
                                cd "$sm_path" &&
-                               eval cmd_status "$orig_args"
+                               eval cmd_status
                        ) ||
                        die "$(eval_gettext "Failed to recurse into submodule path '\$sm_path'")"
                fi
@@ -1010,6 +1032,10 @@ cmd_sync()
                        GIT_QUIET=1
                        shift
                        ;;
+               --recursive)
+                       recursive=1
+                       shift
+                       ;;
                --)
                        shift
                        break
@@ -1051,7 +1077,7 @@ cmd_sync()
 
                if git config "submodule.$name.url" >/dev/null 2>/dev/null
                then
-                       say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
+                       say "$(eval_gettext "Synchronizing submodule url for '\$prefix\$sm_path'")"
                        git config submodule."$name".url "$super_config_url"
 
                        if test -e "$sm_path"/.git
@@ -1061,6 +1087,12 @@ cmd_sync()
                                cd "$sm_path"
                                remote=$(get_default_remote)
                                git config remote."$remote".url "$sub_origin_url"
+
+                               if test -n "$recursive"
+                               then
+                                       prefix="$prefix$sm_path/"
+                                       eval cmd_sync
+                               fi
                        )
                        fi
                fi
diff --git a/git.c b/git.c
index 8788b32..d33f9b3 100644 (file)
--- a/git.c
+++ b/git.c
@@ -17,39 +17,6 @@ const char git_more_info_string[] =
 
 static struct startup_info git_startup_info;
 static int use_pager = -1;
-struct pager_config {
-       const char *cmd;
-       int want;
-       char *value;
-};
-
-static int pager_command_config(const char *var, const char *value, void *data)
-{
-       struct pager_config *c = data;
-       if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) {
-               int b = git_config_maybe_bool(var, value);
-               if (b >= 0)
-                       c->want = b;
-               else {
-                       c->want = 1;
-                       c->value = xstrdup(value);
-               }
-       }
-       return 0;
-}
-
-/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
-int check_pager_config(const char *cmd)
-{
-       struct pager_config c;
-       c.cmd = cmd;
-       c.want = -1;
-       c.value = NULL;
-       git_config(pager_command_config, &c);
-       if (c.value)
-               pager_program = c.value;
-       return c.want;
-}
 
 static void commit_pager_choice(void) {
        switch (use_pager) {
index c852101..c9ced33 100644 (file)
--- a/git.spec
+++ b/git.spec
@@ -1,7 +1,7 @@
 # Pass --without docs to rpmbuild if you don't want the documentation
 
 Name:          git
-Version:       1.8.0
+Version:       1.8.1.3
 Release:       1%{?dist}
 Summary:       Core git tools
 License:       GPL
index 10ed9e5..c6bafe6 100755 (executable)
@@ -270,16 +270,15 @@ our %highlight_basename = (
 our %highlight_ext = (
        # main extensions, defining name of syntax;
        # see files in /usr/share/highlight/langDefs/ directory
-       map { $_ => $_ }
-               qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make),
+       (map { $_ => $_ } qw(py rb java css js tex bib xml awk bat ini spec tcl sql)),
        # alternate extensions, see /etc/highlight/filetypes.conf
-       'h' => 'c',
-       map { $_ => 'sh'  } qw(bash zsh ksh),
-       map { $_ => 'cpp' } qw(cxx c++ cc),
-       map { $_ => 'php' } qw(php3 php4 php5 phps),
-       map { $_ => 'pl'  } qw(perl pm), # perhaps also 'cgi'
-       map { $_ => 'make'} qw(mak mk),
-       map { $_ => 'xml' } qw(xhtml html htm),
+       (map { $_ => 'c'   } qw(c h)),
+       (map { $_ => 'sh'  } qw(sh bash zsh ksh)),
+       (map { $_ => 'cpp' } qw(cpp cxx c++ cc)),
+       (map { $_ => 'php' } qw(php php3 php4 php5 phps)),
+       (map { $_ => 'pl'  } qw(pl perl pm)), # perhaps also 'cgi'
+       (map { $_ => 'make'} qw(make mak mk)),
+       (map { $_ => 'xml' } qw(xml xhtml html htm)),
 );
 
 # You define site-wide feature defaults here; override them with
@@ -541,7 +540,7 @@ our %feature = (
        # $feature{'remote_heads'}{'default'} = [1];
        # To have project specific config enable override in $GITWEB_CONFIG
        # $feature{'remote_heads'}{'override'} = 1;
-       # and in project config gitweb.remote_heads = 0|1;
+       # and in project config gitweb.remoteheads = 0|1;
        'remote_heads' => {
                'sub' => sub { feature_bool('remote_heads', @_) },
                'override' => 0,
@@ -1557,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;
 }
 
@@ -2697,12 +2696,15 @@ sub git_get_project_config {
        # only subsection, if exists, is case sensitive,
        # and not lowercased by 'git config -z -l'
        if (my ($hi, $mi, $lo) = ($key =~ /^([^.]*)\.(.*)\.([^.]*)$/)) {
+               $lo =~ s/_//g;
                $key = join(".", lc($hi), $mi, lc($lo));
+               return if ($lo =~ /\W/ || $hi =~ /\W/);
        } else {
                $key = lc($key);
+               $key =~ s/_//g;
+               return if ($key =~ /\W/);
        }
        $key =~ s/^gitweb\.//;
-       return if ($key =~ m/\W/);
 
        # type sanity check
        if (defined $type) {
@@ -5526,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
@@ -8055,6 +8064,7 @@ sub git_feed {
                $feed_type = 'history';
        }
        $title .= " $feed_type";
+       $title = esc_html($title);
        my $descr = git_get_project_description($project);
        if (defined $descr) {
                $descr = esc_html($descr);
index 0863c61..5f142f6 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 e864fe2..391a712 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/grep.c b/grep.c
index edc7776..4bd1b8b 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -6,6 +6,183 @@
 static int grep_source_load(struct grep_source *gs);
 static int grep_source_is_binary(struct grep_source *gs);
 
+static struct grep_opt grep_defaults;
+
+/*
+ * Initialize the grep_defaults template with hardcoded defaults.
+ * We could let the compiler do this, but without C99 initializers
+ * the code gets unwieldy and unreadable, so...
+ */
+void init_grep_defaults(void)
+{
+       struct grep_opt *opt = &grep_defaults;
+       static int run_once;
+
+       if (run_once)
+               return;
+       run_once++;
+
+       memset(opt, 0, sizeof(*opt));
+       opt->relative = 1;
+       opt->pathname = 1;
+       opt->regflags = REG_NEWLINE;
+       opt->max_depth = -1;
+       opt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
+       opt->extended_regexp_option = 0;
+       strcpy(opt->color_context, "");
+       strcpy(opt->color_filename, "");
+       strcpy(opt->color_function, "");
+       strcpy(opt->color_lineno, "");
+       strcpy(opt->color_match, GIT_COLOR_BOLD_RED);
+       strcpy(opt->color_selected, "");
+       strcpy(opt->color_sep, GIT_COLOR_CYAN);
+       opt->color = -1;
+}
+
+static int parse_pattern_type_arg(const char *opt, const char *arg)
+{
+       if (!strcmp(arg, "default"))
+               return GREP_PATTERN_TYPE_UNSPECIFIED;
+       else if (!strcmp(arg, "basic"))
+               return GREP_PATTERN_TYPE_BRE;
+       else if (!strcmp(arg, "extended"))
+               return GREP_PATTERN_TYPE_ERE;
+       else if (!strcmp(arg, "fixed"))
+               return GREP_PATTERN_TYPE_FIXED;
+       else if (!strcmp(arg, "perl"))
+               return GREP_PATTERN_TYPE_PCRE;
+       die("bad %s argument: %s", opt, arg);
+}
+
+/*
+ * Read the configuration file once and store it in
+ * the grep_defaults template.
+ */
+int grep_config(const char *var, const char *value, void *cb)
+{
+       struct grep_opt *opt = &grep_defaults;
+       char *color = NULL;
+
+       if (userdiff_config(var, value) < 0)
+               return -1;
+
+       if (!strcmp(var, "grep.extendedregexp")) {
+               if (git_config_bool(var, value))
+                       opt->extended_regexp_option = 1;
+               else
+                       opt->extended_regexp_option = 0;
+               return 0;
+       }
+
+       if (!strcmp(var, "grep.patterntype")) {
+               opt->pattern_type_option = parse_pattern_type_arg(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "grep.linenumber")) {
+               opt->linenum = git_config_bool(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "color.grep"))
+               opt->color = git_config_colorbool(var, value);
+       else if (!strcmp(var, "color.grep.context"))
+               color = opt->color_context;
+       else if (!strcmp(var, "color.grep.filename"))
+               color = opt->color_filename;
+       else if (!strcmp(var, "color.grep.function"))
+               color = opt->color_function;
+       else if (!strcmp(var, "color.grep.linenumber"))
+               color = opt->color_lineno;
+       else if (!strcmp(var, "color.grep.match"))
+               color = opt->color_match;
+       else if (!strcmp(var, "color.grep.selected"))
+               color = opt->color_selected;
+       else if (!strcmp(var, "color.grep.separator"))
+               color = opt->color_sep;
+
+       if (color) {
+               if (!value)
+                       return config_error_nonbool(var);
+               color_parse(value, var, color);
+       }
+       return 0;
+}
+
+/*
+ * Initialize one instance of grep_opt and copy the
+ * default values from the template we read the configuration
+ * information in an earlier call to git_config(grep_config).
+ */
+void grep_init(struct grep_opt *opt, const char *prefix)
+{
+       struct grep_opt *def = &grep_defaults;
+
+       memset(opt, 0, sizeof(*opt));
+       opt->prefix = prefix;
+       opt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
+       opt->pattern_tail = &opt->pattern_list;
+       opt->header_tail = &opt->header_list;
+
+       opt->color = def->color;
+       opt->extended_regexp_option = def->extended_regexp_option;
+       opt->pattern_type_option = def->pattern_type_option;
+       opt->linenum = def->linenum;
+       opt->max_depth = def->max_depth;
+       opt->pathname = def->pathname;
+       opt->regflags = def->regflags;
+       opt->relative = def->relative;
+
+       strcpy(opt->color_context, def->color_context);
+       strcpy(opt->color_filename, def->color_filename);
+       strcpy(opt->color_function, def->color_function);
+       strcpy(opt->color_lineno, def->color_lineno);
+       strcpy(opt->color_match, def->color_match);
+       strcpy(opt->color_selected, def->color_selected);
+       strcpy(opt->color_sep, def->color_sep);
+}
+
+void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)
+{
+       if (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)
+               grep_set_pattern_type_option(pattern_type, opt);
+       else if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
+               grep_set_pattern_type_option(opt->pattern_type_option, opt);
+       else if (opt->extended_regexp_option)
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);
+}
+
+void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
+{
+       switch (pattern_type) {
+       case GREP_PATTERN_TYPE_UNSPECIFIED:
+               /* fall through */
+
+       case GREP_PATTERN_TYPE_BRE:
+               opt->fixed = 0;
+               opt->pcre = 0;
+               opt->regflags &= ~REG_EXTENDED;
+               break;
+
+       case GREP_PATTERN_TYPE_ERE:
+               opt->fixed = 0;
+               opt->pcre = 0;
+               opt->regflags |= REG_EXTENDED;
+               break;
+
+       case GREP_PATTERN_TYPE_FIXED:
+               opt->fixed = 1;
+               opt->pcre = 0;
+               opt->regflags &= ~REG_EXTENDED;
+               break;
+
+       case GREP_PATTERN_TYPE_PCRE:
+               opt->fixed = 0;
+               opt->pcre = 1;
+               opt->regflags &= ~REG_EXTENDED;
+               break;
+       }
+}
 
 static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
                                        const char *origin, int no,
@@ -1373,7 +1550,7 @@ int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size)
        struct grep_source gs;
        int r;
 
-       grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL);
+       grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL, NULL);
        gs.buf = buf;
        gs.size = size;
 
@@ -1384,10 +1561,12 @@ int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size)
 }
 
 void grep_source_init(struct grep_source *gs, enum grep_source_type type,
-                     const char *name, const void *identifier)
+                     const char *name, const char *path,
+                     const void *identifier)
 {
        gs->type = type;
        gs->name = name ? xstrdup(name) : NULL;
+       gs->path = path ? xstrdup(path) : NULL;
        gs->buf = NULL;
        gs->size = 0;
        gs->driver = NULL;
@@ -1409,6 +1588,8 @@ void grep_source_clear(struct grep_source *gs)
 {
        free(gs->name);
        gs->name = NULL;
+       free(gs->path);
+       gs->path = NULL;
        free(gs->identifier);
        gs->identifier = NULL;
        grep_source_clear_data(gs);
@@ -1501,7 +1682,8 @@ void grep_source_load_driver(struct grep_source *gs)
                return;
 
        grep_attr_lock();
-       gs->driver = userdiff_find_by_path(gs->name);
+       if (gs->path)
+               gs->driver = userdiff_find_by_path(gs->path);
        if (!gs->driver)
                gs->driver = userdiff_find_by_name("default");
        grep_attr_unlock();
diff --git a/grep.h b/grep.h
index c256ac6..8fc854f 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -138,6 +138,12 @@ struct grep_opt {
        void *output_priv;
 };
 
+extern void init_grep_defaults(void);
+extern int grep_config(const char *var, const char *value, void *);
+extern void grep_init(struct grep_opt *, const char *prefix);
+void grep_set_pattern_type_option(enum grep_pattern_type, struct grep_opt *opt);
+void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
+
 extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
 extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
 extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
@@ -158,11 +164,13 @@ struct grep_source {
        char *buf;
        unsigned long size;
 
+       char *path; /* for attribute lookups */
        struct userdiff_driver *driver;
 };
 
 void grep_source_init(struct grep_source *gs, enum grep_source_type type,
-                     const char *name, const void *identifier);
+                     const char *name, const char *path,
+                     const void *identifier);
 void grep_source_clear_data(struct grep_source *gs);
 void grep_source_clear(struct grep_source *gs);
 void grep_source_load_driver(struct grep_source *gs);
diff --git a/help.c b/help.c
index 2a42ec6..1dfa0b0 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;
diff --git a/http.c b/http.c
index df9bb71..44f3525 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);
        }
@@ -631,6 +632,18 @@ void run_active_slot(struct active_request_slot *slot)
                        FD_ZERO(&excfds);
                        curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
 
+                       /*
+                        * It can happen that curl_multi_timeout returns a pathologically
+                        * long timeout when curl_multi_fdset returns no file descriptors
+                        * to read.  See commit message for more details.
+                        */
+                       if (max_fd < 0 &&
+                           (select_timeout.tv_sec > 0 ||
+                            select_timeout.tv_usec > 50000)) {
+                               select_timeout.tv_sec  = 0;
+                               select_timeout.tv_usec = 50000;
+                       }
+
                        select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
                }
        }
@@ -745,8 +758,7 @@ char *get_remote_object_url(const char *url, const char *hex,
        return strbuf_detach(&buf, NULL);
 }
 
-int handle_curl_result(struct active_request_slot *slot,
-                      struct slot_results *results)
+int handle_curl_result(struct slot_results *results)
 {
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
@@ -759,7 +771,6 @@ int handle_curl_result(struct active_request_slot *slot,
                        return HTTP_NOAUTH;
                } else {
                        credential_fill(&http_auth);
-                       init_curl_http_auth(slot->curl);
                        return HTTP_REAUTH;
                }
        } else {
@@ -821,7 +832,7 @@ static int http_request(const char *url, void *result, int target, int options)
 
        if (start_active_slot(slot)) {
                run_active_slot(slot);
-               ret = handle_curl_result(slot, &results);
+               ret = handle_curl_result(&results);
        } else {
                error("Unable to start HTTP request for %s", url);
                ret = HTTP_START_FAILED;
diff --git a/http.h b/http.h
index 0bd1e84..0a80d30 100644 (file)
--- a/http.h
+++ b/http.h
@@ -78,8 +78,7 @@ extern int start_active_slot(struct active_request_slot *slot);
 extern void run_active_slot(struct active_request_slot *slot);
 extern void finish_active_slot(struct active_request_slot *slot);
 extern void finish_all_active_slots(void);
-extern int handle_curl_result(struct active_request_slot *slot,
-                             struct slot_results *results);
+extern int handle_curl_result(struct slot_results *results);
 
 #ifdef USE_CURL_MULTI
 extern void fill_active_slots(void);
diff --git a/ident.c b/ident.c
index a4bf206..1c123e6 100644 (file)
--- a/ident.c
+++ b/ident.c
 static struct strbuf git_default_name = STRBUF_INIT;
 static struct strbuf git_default_email = STRBUF_INIT;
 static char git_default_date[50];
-int user_ident_explicitly_given;
+
+#define IDENT_NAME_GIVEN 01
+#define IDENT_MAIL_GIVEN 02
+#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
+static int committer_ident_explicitly_given;
+static int author_ident_explicitly_given;
 
 #ifdef NO_GECOS_IN_PWENT
 #define get_gecos(ignored) "&"
@@ -41,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) {
@@ -49,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;
 }
@@ -109,7 +118,8 @@ const char *ident_default_email(void)
 
                if (email && email[0]) {
                        strbuf_addstr(&git_default_email, email);
-                       user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
+                       committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
+                       author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                } else
                        copy_email(xgetpwuid_self(), &git_default_email);
                strbuf_trim(&git_default_email);
@@ -327,6 +337,10 @@ const char *fmt_name(const char *name, const char *email)
 
 const char *git_author_info(int flag)
 {
+       if (getenv("GIT_AUTHOR_NAME"))
+               author_ident_explicitly_given |= IDENT_NAME_GIVEN;
+       if (getenv("GIT_AUTHOR_EMAIL"))
+               author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
        return fmt_ident(getenv("GIT_AUTHOR_NAME"),
                         getenv("GIT_AUTHOR_EMAIL"),
                         getenv("GIT_AUTHOR_DATE"),
@@ -336,16 +350,16 @@ const char *git_author_info(int flag)
 const char *git_committer_info(int flag)
 {
        if (getenv("GIT_COMMITTER_NAME"))
-               user_ident_explicitly_given |= IDENT_NAME_GIVEN;
+               committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
        if (getenv("GIT_COMMITTER_EMAIL"))
-               user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
+               committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
        return fmt_ident(getenv("GIT_COMMITTER_NAME"),
                         getenv("GIT_COMMITTER_EMAIL"),
                         getenv("GIT_COMMITTER_DATE"),
                         flag);
 }
 
-int user_ident_sufficiently_given(void)
+static int ident_is_sufficient(int user_ident_explicitly_given)
 {
 #ifndef WINDOWS
        return (user_ident_explicitly_given & IDENT_MAIL_GIVEN);
@@ -354,6 +368,16 @@ int user_ident_sufficiently_given(void)
 #endif
 }
 
+int committer_ident_sufficiently_given(void)
+{
+       return ident_is_sufficient(committer_ident_explicitly_given);
+}
+
+int author_ident_sufficiently_given(void)
+{
+       return ident_is_sufficient(author_ident_explicitly_given);
+}
+
 int git_ident_config(const char *var, const char *value, void *data)
 {
        if (!strcmp(var, "user.name")) {
@@ -361,7 +385,8 @@ int git_ident_config(const char *var, const char *value, void *data)
                        return config_error_nonbool(var);
                strbuf_reset(&git_default_name);
                strbuf_addstr(&git_default_name, value);
-               user_ident_explicitly_given |= IDENT_NAME_GIVEN;
+               committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
+               author_ident_explicitly_given |= IDENT_NAME_GIVEN;
                return 0;
        }
 
@@ -370,7 +395,8 @@ int git_ident_config(const char *var, const char *value, void *data)
                        return config_error_nonbool(var);
                strbuf_reset(&git_default_email);
                strbuf_addstr(&git_default_email, value);
-               user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
+               committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
+               author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                return 0;
        }
 
index c894930..4f86def 100644 (file)
@@ -540,7 +540,6 @@ void show_log(struct rev_info *opt)
        struct pretty_print_context ctx = {0};
 
        opt->loginfo = NULL;
-       ctx.show_notes = opt->show_notes;
        if (!opt->verbose_header) {
                graph_show_commit(opt->graph);
 
@@ -648,6 +647,18 @@ void show_log(struct rev_info *opt)
        if (!commit->buffer)
                return;
 
+       if (opt->show_notes) {
+               int raw;
+               struct strbuf notebuf = STRBUF_INIT;
+
+               raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
+               format_display_notes(commit->object.sha1, &notebuf,
+                                    get_log_output_encoding(), raw);
+               ctx.notes_message = notebuf.len
+                       ? strbuf_detach(&notebuf, NULL)
+                       : xcalloc(1, 1);
+       }
+
        /*
         * And then the pretty-printed message itself
         */
@@ -664,6 +675,16 @@ void show_log(struct rev_info *opt)
 
        if (opt->add_signoff)
                append_signoff(&msgbuf, opt->add_signoff);
+
+       if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
+           ctx.notes_message && *ctx.notes_message) {
+               if (ctx.fmt == CMIT_FMT_EMAIL) {
+                       strbuf_addstr(&msgbuf, "---\n");
+                       opt->shown_dashes = 1;
+               }
+               strbuf_addstr(&msgbuf, ctx.notes_message);
+       }
+
        if (opt->show_log_size) {
                printf("log size %i\n", (int)msgbuf.len);
                graph_show_oneline(opt->graph);
@@ -689,10 +710,12 @@ void show_log(struct rev_info *opt)
        }
 
        strbuf_release(&msgbuf);
+       free(ctx.notes_message);
 }
 
 int log_tree_diff_flush(struct rev_info *opt)
 {
+       opt->shown_dashes = 0;
        diffcore_std(&opt->diffopt);
 
        if (diff_queue_is_empty()) {
@@ -704,15 +727,16 @@ int log_tree_diff_flush(struct rev_info *opt)
        }
 
        if (opt->loginfo && !opt->no_commit_id) {
-               /* When showing a verbose header (i.e. log message),
-                * and not in --pretty=oneline format, we would want
-                * an extra newline between the end of log and the
-                * output for readability.
-                */
                show_log(opt);
                if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) &&
                    opt->verbose_header &&
                    opt->commit_format != CMIT_FMT_ONELINE) {
+                       /*
+                        * When showing a verbose header (i.e. log message),
+                        * and not in --pretty=oneline format, we would want
+                        * an extra newline between the end of log and the
+                        * diff/diffstat output for readability.
+                        */
                        int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
                        if (opt->diffopt.output_prefix) {
                                struct strbuf *msg = NULL;
@@ -720,9 +744,20 @@ int log_tree_diff_flush(struct rev_info *opt)
                                        opt->diffopt.output_prefix_data);
                                fwrite(msg->buf, msg->len, 1, stdout);
                        }
-                       if ((pch & opt->diffopt.output_format) == pch) {
+
+                       /*
+                        * We may have shown three-dashes line early
+                        * between notes and the log message, in which
+                        * case we only want a blank line after the
+                        * notes without (an extra) three-dashes line.
+                        * Otherwise, we show the three-dashes line if
+                        * we are showing the patch with diffstat, but
+                        * in that case, there is no extra blank line
+                        * after the three-dashes line.
+                        */
+                       if (!opt->shown_dashes &&
+                           (pch & opt->diffopt.output_format) == pch)
                                printf("---");
-                       }
                        putchar('\n');
                }
        }
index 47aa419..ea4b471 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -118,7 +118,7 @@ static char *parse_name_and_email(char *buffer, char **name,
        while (isspace(*nstart) && nstart < left)
                ++nstart;
        nend = left-1;
-       while (isspace(*nend) && nend > nstart)
+       while (nend > nstart && isspace(*nend))
                --nend;
 
        *name = (nstart < nend ? nstart : NULL);
similarity index 94%
rename from merge-file.c
rename to merge-blobs.c
index 7845528..57211bc 100644 (file)
@@ -3,7 +3,7 @@
 #include "xdiff-interface.h"
 #include "ll-merge.h"
 #include "blob.h"
-#include "merge-file.h"
+#include "merge-blobs.h"
 
 static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
 {
@@ -80,7 +80,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
        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 *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;
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.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 d882060..33ba5dc 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 58f3435..9e090a3 100644 (file)
@@ -59,9 +59,4 @@ struct tree *write_tree_from_memory(struct merge_options *o);
 
 int parse_merge_opt(struct merge_options *out, const char *s);
 
-/* builtin/merge.c */
-int try_merge_command(const char *strategy, size_t xopts_nr,
-               const char **xopts, struct commit_list *common,
-               const char *head_arg, struct commit_list *remotes);
-
 #endif
diff --git a/merge.c b/merge.c
new file mode 100644 (file)
index 0000000..70f1000
--- /dev/null
+++ b/merge.c
@@ -0,0 +1,112 @@
+#include "cache.h"
+#include "commit.h"
+#include "run-command.h"
+#include "resolve-undo.h"
+#include "tree-walk.h"
+#include "unpack-trees.h"
+#include "dir.h"
+
+static const char *merge_argument(struct commit *commit)
+{
+       if (commit)
+               return sha1_to_hex(commit->object.sha1);
+       else
+               return EMPTY_TREE_SHA1_HEX;
+}
+
+int try_merge_command(const char *strategy, size_t xopts_nr,
+                     const char **xopts, struct commit_list *common,
+                     const char *head_arg, struct commit_list *remotes)
+{
+       const char **args;
+       int i = 0, x = 0, ret;
+       struct commit_list *j;
+       struct strbuf buf = STRBUF_INIT;
+
+       args = xmalloc((4 + xopts_nr + commit_list_count(common) +
+                       commit_list_count(remotes)) * sizeof(char *));
+       strbuf_addf(&buf, "merge-%s", strategy);
+       args[i++] = buf.buf;
+       for (x = 0; x < xopts_nr; x++) {
+               char *s = xmalloc(strlen(xopts[x])+2+1);
+               strcpy(s, "--");
+               strcpy(s+2, xopts[x]);
+               args[i++] = s;
+       }
+       for (j = common; j; j = j->next)
+               args[i++] = xstrdup(merge_argument(j->item));
+       args[i++] = "--";
+       args[i++] = head_arg;
+       for (j = remotes; j; j = j->next)
+               args[i++] = xstrdup(merge_argument(j->item));
+       args[i] = NULL;
+       ret = run_command_v_opt(args, RUN_GIT_CMD);
+       strbuf_release(&buf);
+       i = 1;
+       for (x = 0; x < xopts_nr; x++)
+               free((void *)args[i++]);
+       for (j = common; j; j = j->next)
+               free((void *)args[i++]);
+       i += 2;
+       for (j = remotes; j; j = j->next)
+               free((void *)args[i++]);
+       free(args);
+       discard_cache();
+       if (read_cache() < 0)
+               die(_("failed to read the cache"));
+       resolve_undo_clear();
+
+       return ret;
+}
+
+int checkout_fast_forward(const unsigned char *head,
+                         const unsigned char *remote,
+                         int overwrite_ignore)
+{
+       struct tree *trees[MAX_UNPACK_TREES];
+       struct unpack_trees_options opts;
+       struct tree_desc t[MAX_UNPACK_TREES];
+       int i, fd, nr_trees = 0;
+       struct dir_struct dir;
+       struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+       refresh_cache(REFRESH_QUIET);
+
+       fd = hold_locked_index(lock_file, 1);
+
+       memset(&trees, 0, sizeof(trees));
+       memset(&opts, 0, sizeof(opts));
+       memset(&t, 0, sizeof(t));
+       if (overwrite_ignore) {
+               memset(&dir, 0, sizeof(dir));
+               dir.flags |= DIR_SHOW_IGNORED;
+               setup_standard_excludes(&dir);
+               opts.dir = &dir;
+       }
+
+       opts.head_idx = 1;
+       opts.src_index = &the_index;
+       opts.dst_index = &the_index;
+       opts.update = 1;
+       opts.verbose_update = 1;
+       opts.merge = 1;
+       opts.fn = twoway_merge;
+       setup_unpack_trees_porcelain(&opts, "merge");
+
+       trees[nr_trees] = parse_tree_indirect(head);
+       if (!trees[nr_trees++])
+               return -1;
+       trees[nr_trees] = parse_tree_indirect(remote);
+       if (!trees[nr_trees++])
+               return -1;
+       for (i = 0; i < nr_trees; i++) {
+               parse_tree(trees[i]);
+               init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
+       }
+       if (unpack_trees(nr_trees, t, &opts))
+               return -1;
+       if (write_cache(fd, active_cache, active_nr) ||
+               commit_locked_index(lock_file))
+               die(_("unable to write new index file"));
+       return 0;
+}
index 1a45c1b..295361a 100644 (file)
@@ -1,5 +1,30 @@
 diff_cmd () {
+       # p4merge does not like /dev/null
+       rm_local=
+       rm_remote=
+       if test "/dev/null" = "$LOCAL"
+       then
+               LOCAL="./p4merge-dev-null.LOCAL.$$"
+               >"$LOCAL"
+               rm_local=true
+       fi
+       if test "/dev/null" = "$REMOTE"
+       then
+               REMOTE="./p4merge-dev-null.REMOTE.$$"
+               >"$REMOTE"
+               rm_remote=true
+       fi
+
        "$merge_tool_path" "$LOCAL" "$REMOTE"
+
+       if test -n "$rm_local"
+       then
+               rm -f "$LOCAL"
+       fi
+       if test -n "$rm_remote"
+       then
+               rm -f "$REMOTE"
+       fi
 }
 
 merge_cmd () {
diff --git a/notes.c b/notes.c
index bc454e1..f63fd57 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -848,15 +848,16 @@ int combine_notes_ignore(unsigned char *cur_sha1,
        return 0;
 }
 
-static int string_list_add_note_lines(struct string_list *sort_uniq_list,
+/*
+ * Add the lines from the named object to list, with trailing
+ * newlines removed.
+ */
+static int string_list_add_note_lines(struct string_list *list,
                                      const unsigned char *sha1)
 {
        char *data;
        unsigned long len;
        enum object_type t;
-       struct strbuf buf = STRBUF_INIT;
-       struct strbuf **lines = NULL;
-       int i, list_index;
 
        if (is_null_sha1(sha1))
                return 0;
@@ -868,24 +869,14 @@ static int string_list_add_note_lines(struct string_list *sort_uniq_list,
                return t != OBJ_BLOB || !data;
        }
 
-       strbuf_attach(&buf, data, len, len + 1);
-       lines = strbuf_split(&buf, '\n');
-
-       for (i = 0; lines[i]; i++) {
-               if (lines[i]->buf[lines[i]->len - 1] == '\n')
-                       strbuf_setlen(lines[i], lines[i]->len - 1);
-               if (!lines[i]->len)
-                       continue; /* skip empty lines */
-               list_index = string_list_find_insert_index(sort_uniq_list,
-                                                          lines[i]->buf, 0);
-               if (list_index < 0)
-                       continue; /* skip duplicate lines */
-               string_list_insert_at_index(sort_uniq_list, list_index,
-                                           lines[i]->buf);
-       }
-
-       strbuf_list_free(lines);
-       strbuf_release(&buf);
+       /*
+        * If the last line of the file is EOL-terminated, this will
+        * add an empty string to the list.  But it will be removed
+        * later, along with any empty strings that came from empty
+        * lines within the file.
+        */
+       string_list_split(list, data, '\n', -1);
+       free(data);
        return 0;
 }
 
@@ -901,7 +892,7 @@ static int string_list_join_lines_helper(struct string_list_item *item,
 int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
                const unsigned char *new_sha1)
 {
-       struct string_list sort_uniq_list = { NULL, 0, 0, 1 };
+       struct string_list sort_uniq_list = STRING_LIST_INIT_DUP;
        struct strbuf buf = STRBUF_INIT;
        int ret = 1;
 
@@ -910,6 +901,9 @@ int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
                goto out;
        if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
                goto out;
+       string_list_remove_empty_items(&sort_uniq_list, 0);
+       sort_string_list(&sort_uniq_list);
+       string_list_remove_duplicates(&sort_uniq_list, 0);
 
        /* create a new blob object from sort_uniq_list */
        if (for_each_string_list(&sort_uniq_list,
@@ -949,23 +943,18 @@ void string_list_add_refs_by_glob(struct string_list *list, const char *glob)
 void string_list_add_refs_from_colon_sep(struct string_list *list,
                                         const char *globs)
 {
-       struct strbuf globbuf = STRBUF_INIT;
-       struct strbuf **split;
+       struct string_list split = STRING_LIST_INIT_NODUP;
+       char *globs_copy = xstrdup(globs);
        int i;
 
-       strbuf_addstr(&globbuf, globs);
-       split = strbuf_split(&globbuf, ':');
+       string_list_split_in_place(&split, globs_copy, ':', -1);
+       string_list_remove_empty_items(&split, 0);
 
-       for (i = 0; split[i]; i++) {
-               if (!split[i]->len)
-                       continue;
-               if (split[i]->buf[split[i]->len-1] == ':')
-                       strbuf_setlen(split[i], split[i]->len-1);
-               string_list_add_refs_by_glob(list, split[i]->buf);
-       }
+       for (i = 0; i < split.nr; i++)
+               string_list_add_refs_by_glob(list, split.items[i].string);
 
-       strbuf_list_free(split);
-       strbuf_release(&globbuf);
+       string_list_clear(&split, 0);
+       free(globs_copy);
 }
 
 static int notes_display_config(const char *k, const char *v, void *cb)
@@ -1204,10 +1193,11 @@ void free_notes(struct notes_tree *t)
  * If the given notes_tree is NULL, the internal/default notes_tree will be
  * used instead.
  *
- * 'flags' is a bitwise combination of the flags for format_display_notes.
+ * (raw != 0) gives the %N userformat; otherwise, the note message is given
+ * for human consumption.
  */
 static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
-                       struct strbuf *sb, const char *output_encoding, int flags)
+                       struct strbuf *sb, const char *output_encoding, int raw)
 {
        static const char utf8[] = "utf-8";
        const unsigned char *sha1;
@@ -1231,7 +1221,7 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
        }
 
        if (output_encoding && *output_encoding &&
-                       strcmp(utf8, output_encoding)) {
+           !is_encoding_utf8(output_encoding)) {
                char *reencoded = reencode_string(msg, output_encoding, utf8);
                if (reencoded) {
                        free(msg);
@@ -1244,7 +1234,7 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
        if (msglen && msg[msglen - 1] == '\n')
                msglen--;
 
-       if (flags & NOTES_SHOW_HEADER) {
+       if (!raw) {
                const char *ref = t->ref;
                if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) {
                        strbuf_addstr(sb, "\nNotes:\n");
@@ -1260,7 +1250,7 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
        for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {
                linelen = strchrnul(msg_p, '\n') - msg_p;
 
-               if (flags & NOTES_INDENT)
+               if (!raw)
                        strbuf_addstr(sb, "    ");
                strbuf_add(sb, msg_p, linelen);
                strbuf_addch(sb, '\n');
@@ -1270,13 +1260,13 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
 }
 
 void format_display_notes(const unsigned char *object_sha1,
-                         struct strbuf *sb, const char *output_encoding, int flags)
+                         struct strbuf *sb, const char *output_encoding, int raw)
 {
        int i;
        assert(display_notes_trees);
        for (i = 0; display_notes_trees[i]; i++)
                format_note(display_notes_trees[i], object_sha1, sb,
-                           output_encoding, flags);
+                           output_encoding, raw);
 }
 
 int copy_note(struct notes_tree *t,
diff --git a/notes.h b/notes.h
index 3592b19..3324c48 100644 (file)
--- a/notes.h
+++ b/notes.h
@@ -237,10 +237,6 @@ void prune_notes(struct notes_tree *t, int flags);
  */
 void free_notes(struct notes_tree *t);
 
-/* Flags controlling how notes are formatted */
-#define NOTES_SHOW_HEADER 1
-#define NOTES_INDENT 2
-
 struct string_list;
 
 struct display_notes_opt {
@@ -274,7 +270,7 @@ void init_display_notes(struct display_notes_opt *opt);
  * You *must* call init_display_notes() before using this function.
  */
 void format_display_notes(const unsigned char *object_sha1,
-                         struct strbuf *sb, const char *output_encoding, int flags);
+                         struct strbuf *sb, const char *output_encoding, int raw);
 
 /*
  * Load the notes tree from each ref listed in 'refs'.  The output is
diff --git a/pager.c b/pager.c
index 4dcb08d..c1ecf65 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -6,26 +6,17 @@
 #define DEFAULT_PAGER "less"
 #endif
 
+struct pager_config {
+       const char *cmd;
+       int want;
+       char *value;
+};
+
 /*
  * This is split up from the rest of git so that we can do
  * something different on Windows.
  */
 
-#ifndef WIN32
-static void pager_preexec(void)
-{
-       /*
-        * Work around bug in "less" by not starting it until we
-        * have real input
-        */
-       fd_set in;
-
-       FD_ZERO(&in);
-       FD_SET(0, &in);
-       select(1, &in, NULL, &in, NULL);
-}
-#endif
-
 static const char *pager_argv[] = { NULL, NULL };
 static struct child_process pager_process;
 
@@ -93,9 +84,6 @@ void setup_pager(void)
                static const char *env[] = { "LESS=FRSX", NULL };
                pager_process.env = env;
        }
-#ifndef WIN32
-       pager_process.preexec_cb = pager_preexec;
-#endif
        if (start_command(&pager_process))
                return;
 
@@ -159,3 +147,31 @@ int decimal_width(int number)
                i *= 10;
        return width;
 }
+
+static int pager_command_config(const char *var, const char *value, void *data)
+{
+       struct pager_config *c = data;
+       if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) {
+               int b = git_config_maybe_bool(var, value);
+               if (b >= 0)
+                       c->want = b;
+               else {
+                       c->want = 1;
+                       c->value = xstrdup(value);
+               }
+       }
+       return 0;
+}
+
+/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
+int check_pager_config(const char *cmd)
+{
+       struct pager_config c;
+       c.cmd = cmd;
+       c.want = -1;
+       c.value = NULL;
+       git_config(pager_command_config, &c);
+       if (c.value)
+               pager_program = c.value;
+       return c.want;
+}
diff --git a/path.c b/path.c
index cbbdf7d..d3d3f8b 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 497f420..931047c 100644 (file)
@@ -58,7 +58,7 @@ require Exporter;
                 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
                 temp_acquire temp_release temp_reset temp_path);
 
 
@@ -511,6 +511,58 @@ C<git --html-path>). Useful mostly only internally.
 
 sub html_path { command_oneline('--html-path') }
 
+=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 ()
 
index 3a6f8af..74daa7a 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 0db9a9b..0e8ed54 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -1,21 +1,21 @@
 # German translations for Git.
-# Copyright (C) 2010-2012 Ralf Thielow <ralf.thielow@googlemail.com>
+# Copyright (C) 2010-2012 Ralf Thielow <ralf.thielow@gmail.com>
 # This file is distributed under the same license as the Git package.
-# Ralf Thielow <ralf.thielow@googlemail.com>, 2010, 2011, 2012.
+# Ralf Thielow <ralf.thielow@gmail.com>, 2010, 2011, 2012.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 1.7.12\n"
+"Project-Id-Version: git 1.8.1\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-09-05 06:20+0800\n"
-"PO-Revision-Date: 2012-03-28 18:46+0200\n"
-"Last-Translator: Ralf Thielow <ralf.thielow@googlemail.com>\n"
-"Language-Team: German\n"
+"POT-Creation-Date: 2012-11-30 12:40+0800\n"
+"PO-Revision-Date: 2012-10-02 19:35+0200\n"
+"Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
+"Language-Team: German <>\n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
 
 #: advice.c:40
 #, c-format
@@ -38,6 +38,101 @@ msgstr ""
 "um die Auflösung entsprechend zu markieren und einzutragen,\n"
 "oder benutze 'git commit -a'."
 
+#: archive.c:10
+msgid "git archive [options] <tree-ish> [<path>...]"
+msgstr "git archive [Optionen] <Versionsreferenz> [<Pfad>...]"
+
+#: archive.c:11
+msgid "git archive --list"
+msgstr "git archive --list"
+
+#: archive.c:12
+msgid ""
+"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
+msgstr ""
+"git archive --remote <Projektarchiv> [--exec <Programm>] [Optionen] "
+"<Versionsreferenz> [Pfad...]"
+
+#: archive.c:13
+msgid "git archive --remote <repo> [--exec <cmd>] --list"
+msgstr "git archive --remote <Projektarchiv> [--exec <Programm>] --list"
+
+#: archive.c:322
+msgid "fmt"
+msgstr "Format"
+
+#: archive.c:322
+msgid "archive format"
+msgstr "Ausgabeformat"
+
+#: archive.c:323 builtin/log.c:1084
+msgid "prefix"
+msgstr "Prefix"
+
+#: archive.c:324
+msgid "prepend prefix to each pathname in the archive"
+msgstr "stellt einen Präfix vor jeden Pfadnamen in der Ausgabe"
+
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390
+#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540
+#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149
+msgid "file"
+msgstr "Datei"
+
+#: archive.c:326 builtin/archive.c:92
+msgid "write the archive to this file"
+msgstr "schreibt die Ausgabe in diese Datei"
+
+#: archive.c:328
+msgid "read .gitattributes in working directory"
+msgstr "liest .gitattributes aus dem Arbeitsverzeichnis"
+
+#: archive.c:329
+msgid "report archived files on stderr"
+msgstr "gibt archivierte Dateien in der Standard-Fehlerausgabe aus"
+
+#: archive.c:330
+msgid "store only"
+msgstr "nur speichern"
+
+#: archive.c:331
+msgid "compress faster"
+msgstr "schneller komprimieren"
+
+#: archive.c:339
+msgid "compress better"
+msgstr "besser komprimieren"
+
+#: archive.c:342
+msgid "list supported archive formats"
+msgstr "listet unterstützte Ausgabeformate auf"
+
+#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
+msgid "repo"
+msgstr "Projektarchiv"
+
+#: archive.c:345 builtin/archive.c:94
+msgid "retrieve the archive from remote repository <repo>"
+msgstr "ruft das Archiv von externem Projektarchiv <Projektarchiv> ab"
+
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619
+msgid "command"
+msgstr "Programm"
+
+#: archive.c:347 builtin/archive.c:96
+msgid "path to the remote git-upload-archive command"
+msgstr "Pfad zum externen \"git-upload-archive\"-Programm"
+
+#: attr.c:259
+msgid ""
+"Negative patterns are forbidden in git attributes\n"
+"Use '\\!' for literal leading exclamation."
+msgstr ""
+"Verneinende Muster sind in Git-Attributen verboten.\n"
+"Benutze '\\!' für führende Ausrufezeichen."
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
@@ -48,7 +143,7 @@ msgstr "'%s' sieht nicht wie eine v2 Paketdatei aus"
 msgid "unrecognized header: %s%s (%d)"
 msgstr "nicht erkannter Kopfbereich: %s%s (%d)"
 
-#: bundle.c:89 builtin/commit.c:699
+#: bundle.c:89 builtin/commit.c:674
 #, c-format
 msgid "could not open '%s'"
 msgstr "Konnte '%s' nicht öffnen"
@@ -57,8 +152,8 @@ msgstr "Konnte '%s' nicht öffnen"
 msgid "Repository lacks these prerequisite commits:"
 msgstr "Dem Projektarchiv fehlen folgende vorausgesetzte Versionen:"
 
-#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290
-#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
+#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290
+#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
@@ -85,7 +180,7 @@ msgstr[1] "Das Paket benötigt diese %d Referenzen"
 msgid "rev-list died"
 msgstr "\"rev-list\" abgebrochen"
 
-#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "nicht erkanntes Argument: %s"
@@ -116,12 +211,12 @@ msgstr "kann '%s' nicht erstellen"
 msgid "index-pack died"
 msgstr "Erstellung der Paketindexdatei abgebrochen"
 
-#: commit.c:48
+#: commit.c:50
 #, c-format
 msgid "could not parse %s"
 msgstr "konnte %s nicht parsen"
 
-#: commit.c:50
+#: commit.c:52
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s ist keine Version!"
@@ -211,18 +306,24 @@ msgid_plural "%lu years ago"
 msgstr[0] "vor %lu Jahr"
 msgstr[1] "vor %lu Jahren"
 
-#: diff.c:105
+#: diff.c:111
 #, c-format
-msgid "  Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
 msgstr ""
-"  Fehler beim Parsen des abgeschnittenen \"dirstat\" Prozentsatzes '%.*s'\n"
+"  Fehler beim Parsen des abgeschnittenen \"dirstat\" Prozentsatzes '%s'\n"
+
+#: diff.c:116
+#, c-format
+msgid "  Unknown dirstat parameter '%s'\n"
+msgstr "  Unbekannter \"dirstat\" Parameter '%s'\n"
 
-#: diff.c:110
+#: diff.c:194
 #, c-format
-msgid "  Unknown dirstat parameter '%.*s'\n"
-msgstr "  Unbekannter \"dirstat\" Parameter '%.*s'\n"
+msgid "Unknown value for 'diff.submodule' config variable: '%s'"
+msgstr ""
+"Unbekannter Wert in Konfigurationsvariable 'diff.dirstat': '%s'"
 
-#: diff.c:210
+#: diff.c:237
 #, c-format
 msgid ""
 "Found errors in 'diff.dirstat' config variable:\n"
@@ -231,32 +332,7 @@ msgstr ""
 "Fehler in 'diff.dirstat' Konfigurationsvariable gefunden:\n"
 "%s"
 
-#: diff.c:1401
-msgid " 0 files changed"
-msgstr " 0 Dateien geändert"
-
-#: diff.c:1405
-#, c-format
-msgid " %d file changed"
-msgid_plural " %d files changed"
-msgstr[0] " %d Datei geändert"
-msgstr[1] " %d Dateien geändert"
-
-#: diff.c:1422
-#, c-format
-msgid ", %d insertion(+)"
-msgid_plural ", %d insertions(+)"
-msgstr[0] ", %d Zeile hinzugefügt(+)"
-msgstr[1] ", %d Zeilen hinzugefügt(+)"
-
-#: diff.c:1433
-#, c-format
-msgid ", %d deletion(-)"
-msgid_plural ", %d deletions(-)"
-msgstr[0] ", %d Zeile entfernt(-)"
-msgstr[1] ", %d Zeilen entfernt(-)"
-
-#: diff.c:3460
+#: diff.c:3494
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -265,6 +341,12 @@ msgstr ""
 "Fehler beim Parsen des --dirstat/-X Optionsparameters:\n"
 "%s"
 
+#: diff.c:3508
+#,  c-format
+msgid "Failed to parse --submodule option parameter: '%s'"
+msgstr ""
+"Fehler beim Parsen des --submodule Optionsparameters: '%s'"
+
 #: gpg-interface.c:59
 msgid "could not run gpg."
 msgstr "konnte gpg nicht ausführen"
@@ -277,17 +359,17 @@ msgstr "gpg hat die Daten nicht akzeptiert"
 msgid "gpg failed to sign the data"
 msgstr "gpg beim Signieren der Daten fehlgeschlagen"
 
-#: grep.c:1320
+#: grep.c:1622
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "'%s': konnte nicht lesen %s"
 
-#: grep.c:1337
+#: grep.c:1639
 #, c-format
 msgid "'%s': %s"
 msgstr "'%s': %s"
 
-#: grep.c:1348
+#: grep.c:1650
 #, c-format
 msgid "'%s': short read %s"
 msgstr "'%s': read() zu kurz %s"
@@ -347,6 +429,15 @@ msgstr[1] ""
 "\n"
 "Hast du eines von diesen gemeint?"
 
+#: merge.c:56
+msgid "failed to read the cache"
+msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
+
+#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
+#: builtin/clone.c:586
+msgid "unable to write new index file"
+msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+
 #: merge-recursive.c:190
 #, c-format
 msgid "(bad commit)\n"
@@ -407,20 +498,20 @@ msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'"
 msgid "do not know what to do with %06o %s '%s'"
 msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
 
-#: merge-recursive.c:921
+#: merge-recursive.c:922
 msgid "Failed to execute internal merge"
 msgstr "Fehler bei Ausführung der internen Zusammenführung"
 
-#: merge-recursive.c:925
+#: merge-recursive.c:926
 #, c-format
 msgid "Unable to add %s to database"
 msgstr "Konnte %s nicht zur Datenbank hinzufügen"
 
-#: merge-recursive.c:941
+#: merge-recursive.c:942
 msgid "unsupported object type in the tree"
 msgstr "nicht unterstützter Objekttyp im Baum"
 
-#: merge-recursive.c:1020 merge-recursive.c:1034
+#: merge-recursive.c:1021 merge-recursive.c:1035
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -429,7 +520,7 @@ msgstr ""
 "KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
 "im Arbeitsbereich gelassen."
 
-#: merge-recursive.c:1026 merge-recursive.c:1039
+#: merge-recursive.c:1027 merge-recursive.c:1040
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -438,20 +529,20 @@ msgstr ""
 "KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
 "im Arbeitsbereich bei %s gelassen."
 
-#: merge-recursive.c:1080
+#: merge-recursive.c:1081
 msgid "rename"
 msgstr "umbenennen"
 
-#: merge-recursive.c:1080
+#: merge-recursive.c:1081
 msgid "renamed"
 msgstr "umbenannt"
 
-#: merge-recursive.c:1136
+#: merge-recursive.c:1137
 #, c-format
 msgid "%s is a directory in %s adding as %s instead"
 msgstr "%s ist ein Verzeichnis in %s, füge es stattdessen als %s hinzu"
 
-#: merge-recursive.c:1158
+#: merge-recursive.c:1159
 #, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
@@ -460,148 +551,148 @@ msgstr ""
 "KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Zweig \"%s\" "
 "und \"%s\"->\"%s\" in Zweig \"%s\"%s"
 
-#: merge-recursive.c:1163
+#: merge-recursive.c:1164
 msgid " (left unresolved)"
 msgstr " (bleibt unaufgelöst)"
 
-#: merge-recursive.c:1217
+#: merge-recursive.c:1218
 #, c-format
 msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
 msgstr ""
 "KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s "
 "in %s"
 
-#: merge-recursive.c:1247
+#: merge-recursive.c:1248
 #, c-format
 msgid "Renaming %s to %s and %s to %s instead"
 msgstr "Benenne stattdessen %s nach %s und %s nach %s um"
 
-#: merge-recursive.c:1446
+#: merge-recursive.c:1447
 #, c-format
 msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
 msgstr ""
 "KONFLIKT (umbenennen/hinzufügen): Benenne um %s->%s in %s. %s hinzugefügt in "
 "%s"
 
-#: merge-recursive.c:1456
+#: merge-recursive.c:1457
 #, c-format
 msgid "Adding merged %s"
 msgstr "Füge zusammengeführte Datei %s hinzu"
 
-#: merge-recursive.c:1461 merge-recursive.c:1659
+#: merge-recursive.c:1462 merge-recursive.c:1660
 #, c-format
 msgid "Adding as %s instead"
 msgstr "Füge stattdessen als %s hinzu"
 
-#: merge-recursive.c:1512
+#: merge-recursive.c:1513
 #, c-format
 msgid "cannot read object %s"
 msgstr "kann Objekt %s nicht lesen"
 
-#: merge-recursive.c:1515
+#: merge-recursive.c:1516
 #, c-format
 msgid "object %s is not a blob"
 msgstr "Objekt %s ist kein Blob"
 
-#: merge-recursive.c:1563
+#: merge-recursive.c:1564
 msgid "modify"
 msgstr "ändern"
 
-#: merge-recursive.c:1563
+#: merge-recursive.c:1564
 msgid "modified"
 msgstr "geändert"
 
-#: merge-recursive.c:1573
+#: merge-recursive.c:1574
 msgid "content"
 msgstr "Inhalt"
 
-#: merge-recursive.c:1580
+#: merge-recursive.c:1581
 msgid "add/add"
 msgstr "hinzufügen/hinzufügen"
 
-#: merge-recursive.c:1614
+#: merge-recursive.c:1615
 #, c-format
 msgid "Skipped %s (merged same as existing)"
 msgstr "%s ausgelassen (Ergebnis der Zusammenführung existiert bereits)"
 
-#: merge-recursive.c:1628
+#: merge-recursive.c:1629
 #, c-format
 msgid "Auto-merging %s"
 msgstr "automatische Zusammenführung von %s"
 
-#: merge-recursive.c:1632 git-submodule.sh:869
+#: merge-recursive.c:1633 git-submodule.sh:893
 msgid "submodule"
 msgstr "Unterprojekt"
 
-#: merge-recursive.c:1633
+#: merge-recursive.c:1634
 #, c-format
 msgid "CONFLICT (%s): Merge conflict in %s"
 msgstr "KONFLIKT (%s): Zusammenführungskonflikt in %s"
 
-#: merge-recursive.c:1723
+#: merge-recursive.c:1724
 #, c-format
 msgid "Removing %s"
 msgstr "Entferne %s"
 
-#: merge-recursive.c:1748
+#: merge-recursive.c:1749
 msgid "file/directory"
 msgstr "Datei/Verzeichnis"
 
-#: merge-recursive.c:1754
+#: merge-recursive.c:1755
 msgid "directory/file"
 msgstr "Verzeichnis/Datei"
 
-#: merge-recursive.c:1759
+#: merge-recursive.c:1760
 #, c-format
 msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
 msgstr ""
 "KONFLIKT (%s): Es existiert bereits ein Verzeichnis %s in %s. Füge %s als %s "
 "hinzu."
 
-#: merge-recursive.c:1769
+#: merge-recursive.c:1770
 #, c-format
 msgid "Adding %s"
 msgstr "Füge %s hinzu"
 
-#: merge-recursive.c:1786
+#: merge-recursive.c:1787
 msgid "Fatal merge failure, shouldn't happen."
 msgstr "Fataler Fehler bei der Zusammenführung. Sollte nicht passieren."
 
-#: merge-recursive.c:1805
+#: merge-recursive.c:1806
 msgid "Already up-to-date!"
 msgstr "Bereits aktuell!"
 
-#: merge-recursive.c:1814
+#: merge-recursive.c:1815
 #, c-format
 msgid "merging of trees %s and %s failed"
 msgstr "Zusammenführen der Bäume %s und %s fehlgeschlagen"
 
-#: merge-recursive.c:1844
+#: merge-recursive.c:1845
 #, c-format
 msgid "Unprocessed path??? %s"
 msgstr "unverarbeiteter Pfad??? %s"
 
-#: merge-recursive.c:1889
+#: merge-recursive.c:1890
 msgid "Merging:"
 msgstr "Zusammenführung:"
 
-#: merge-recursive.c:1902
+#: merge-recursive.c:1903
 #, c-format
 msgid "found %u common ancestor:"
 msgid_plural "found %u common ancestors:"
 msgstr[0] "%u gemeinsamen Vorfahren gefunden"
 msgstr[1] "%u gemeinsame Vorfahren gefunden"
 
-#: merge-recursive.c:1939
+#: merge-recursive.c:1940
 msgid "merge returned no commit"
 msgstr "Zusammenführung hat keine Version zurückgegeben"
 
-#: merge-recursive.c:1996
+#: merge-recursive.c:1997
 #, c-format
 msgid "Could not parse object '%s'"
 msgstr "Konnte Objekt '%s' nicht parsen."
 
-#: merge-recursive.c:2008 builtin/merge.c:696
+#: merge-recursive.c:2009 builtin/merge.c:643
 msgid "Unable to write index."
 msgstr "Konnte Bereitstellung nicht schreiben."
 
@@ -633,7 +724,11 @@ msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
 msgstr[0] "Dein Zweig ist vor '%s' um %d Version.\n"
 msgstr[1] "Dein Zweig ist vor '%s' um %d Versionen.\n"
 
-#: remote.c:1638
+#: remote.c:1637
+msgid "  (use \"git push\" to publish your local commits)\n"
+msgstr "  (benutze \"git push\" um deine lokalen Versionen herauszubringen)\n"
+
+#: remote.c:1640
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -644,7 +739,12 @@ msgstr[1] ""
 "Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult "
 "werden.\n"
 
-#: remote.c:1646
+#: remote.c:1647
+msgid "  (use \"git pull\" to update your local branch)\n"
+msgstr ""
+"  (benutze \"git pull\" um deinen lokalen Zweig zu aktualisieren)\n"
+
+#: remote.c:1650
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -659,19 +759,24 @@ msgstr[1] ""
 "Dein Zweig und '%s' sind divergiert,\n"
 "und haben jeweils %d und %d unterschiedliche Versionen.\n"
 
-#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
-#: builtin/merge.c:1087 builtin/merge.c:1097
+#: remote.c:1659
+msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
+msgstr ""
+"  (benutze \"git pull\" um deinen Zweig mit dem externen zusammenzuführen)\n"
+
+#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
+#: builtin/merge.c:994
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "Konnte '%s' nicht zum Schreiben öffnen."
 
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
-#: builtin/merge.c:1089 builtin/merge.c:1102
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
+#: builtin/merge.c:999
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "Konnte nicht nach '%s' schreiben."
 
-#: sequencer.c:144
+#: sequencer.c:146
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
@@ -679,7 +784,7 @@ msgstr ""
 "nach Auflösung der Konflikte, markiere die korrigierten Pfade\n"
 "mit 'git add <Pfade>' oder 'git rm <Pfade>'"
 
-#: sequencer.c:147
+#: sequencer.c:149
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'\n"
@@ -689,74 +794,74 @@ msgstr ""
 "mit 'git add <Pfade>' oder 'git rm <Pfade>'und trage das Ergebnis ein mit "
 "'git commit'"
 
-#: sequencer.c:160 sequencer.c:758 sequencer.c:841
+#: sequencer.c:162 sequencer.c:770 sequencer.c:853
 #, c-format
 msgid "Could not write to %s"
 msgstr "Konnte nicht nach %s schreiben"
 
-#: sequencer.c:163
+#: sequencer.c:165
 #, c-format
 msgid "Error wrapping up %s"
 msgstr "Fehler bei Nachbereitung von %s"
 
-#: sequencer.c:178
+#: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr ""
 "Deine lokalen Änderungen würden von \"cherry-pick\" überschrieben werden."
 
-#: sequencer.c:180
+#: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
 msgstr "Deine lokalen Änderungen würden von \"revert\" überschrieben werden."
 
-#: sequencer.c:183
+#: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
 msgstr "Trage deine Änderungen ein oder benutze \"stash\" um fortzufahren."
 
 #. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:233
+#: sequencer.c:235
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: Konnte neue Bereitstellungsdatei nicht schreiben"
 
-#: sequencer.c:261
+#: sequencer.c:266
 msgid "Could not resolve HEAD commit\n"
 msgstr "Konnte Version der Zweigspitze (HEAD) nicht auflösen\n"
 
-#: sequencer.c:282
+#: sequencer.c:287
 msgid "Unable to update cache tree\n"
 msgstr "Konnte zwischengespeicherten Baum nicht aktualisieren\n"
 
-#: sequencer.c:324
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr "Konnte Version %s nicht parsen\n"
 
-#: sequencer.c:329
+#: sequencer.c:337
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr "Konnte Elternversion %s nicht parsen\n"
 
-#: sequencer.c:395
+#: sequencer.c:403
 msgid "Your index file is unmerged."
 msgstr "Deine Bereitstellungsdatei ist nicht zusammengeführt."
 
-#: sequencer.c:398
+#: sequencer.c:406
 msgid "You do not have a valid HEAD"
 msgstr "Du hast keine gültige Zweigspitze (HEAD)"
 
-#: sequencer.c:413
+#: sequencer.c:421
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
 msgstr ""
 "Version %s ist eine Zusammenführung, aber die Option -m wurde nicht "
 "angegeben."
 
-#: sequencer.c:421
+#: sequencer.c:429
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr "Version %s hat keinen Elternteil %d"
 
-#: sequencer.c:425
+#: sequencer.c:433
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
 msgstr ""
@@ -764,145 +869,145 @@ msgstr ""
 
 #. TRANSLATORS: The first %s will be "revert" or
 #. "cherry-pick", the second %s a SHA1
-#: sequencer.c:436
+#: sequencer.c:444
 #, c-format
 msgid "%s: cannot parse parent commit %s"
 msgstr "%s: kann Elternversion %s nicht parsen"
 
-#: sequencer.c:440
+#: sequencer.c:448
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr "Kann keine Versionsbeschreibung für %s bekommen"
 
-#: sequencer.c:524
+#: sequencer.c:532
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "Konnte %s nicht zurücksetzen... %s"
 
-#: sequencer.c:525
+#: sequencer.c:533
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "Konnte %s nicht anwenden... %s"
 
-#: sequencer.c:553
+#: sequencer.c:565
 msgid "empty commit set passed"
 msgstr "leere Menge von Versionen übergeben"
 
-#: sequencer.c:561
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: Fehler beim Lesen der Bereitstellung"
 
-#: sequencer.c:566
+#: sequencer.c:578
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: Fehler beim Aktualisieren der Bereitstellung"
 
-#: sequencer.c:624
+#: sequencer.c:636
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr "Kann %s nicht während eines %s durchführen"
 
-#: sequencer.c:646
+#: sequencer.c:658
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Konnte Zeile %d nicht parsen."
 
-#: sequencer.c:651
+#: sequencer.c:663
 msgid "No commits parsed."
 msgstr "Keine Versionen geparst."
 
-#: sequencer.c:664
+#: sequencer.c:676
 #, c-format
 msgid "Could not open %s"
 msgstr "Konnte %s nicht öffnen"
 
-#: sequencer.c:668
+#: sequencer.c:680
 #, c-format
 msgid "Could not read %s."
 msgstr "Konnte %s nicht lesen."
 
-#: sequencer.c:675
+#: sequencer.c:687
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr "Unbenutzbares Instruktionsblatt: %s"
 
-#: sequencer.c:703
+#: sequencer.c:715
 #, c-format
 msgid "Invalid key: %s"
 msgstr "Ungültiger Schlüssel: %s"
 
-#: sequencer.c:706
+#: sequencer.c:718
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Ungültiger Wert für %s: %s"
 
-#: sequencer.c:718
+#: sequencer.c:730
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr "Fehlerhaftes Optionsblatt: %s"
 
-#: sequencer.c:739
+#: sequencer.c:751
 msgid "a cherry-pick or revert is already in progress"
 msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang"
 
-#: sequencer.c:740
+#: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr "versuche \"git cherry-pick (--continue | --quit | --abort)\""
 
-#: sequencer.c:744
+#: sequencer.c:756
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr "Konnte \"sequencer\"-Verzeichnis %s nicht erstellen"
 
-#: sequencer.c:760 sequencer.c:845
+#: sequencer.c:772 sequencer.c:857
 #, c-format
 msgid "Error wrapping up %s."
 msgstr "Fehler beim Einpacken von %s."
 
-#: sequencer.c:779 sequencer.c:913
+#: sequencer.c:791 sequencer.c:925
 msgid "no cherry-pick or revert in progress"
 msgstr "kein \"cherry-pick\" oder \"revert\" im Gang"
 
-#: sequencer.c:781
+#: sequencer.c:793
 msgid "cannot resolve HEAD"
 msgstr "kann Zweigspitze (HEAD) nicht auflösen"
 
-#: sequencer.c:783
+#: sequencer.c:795
 msgid "cannot abort from a branch yet to be born"
 msgstr "kann nicht abbrechen: bin auf einem Zweig, der noch geboren wird"
 
-#: sequencer.c:805 builtin/apply.c:3987
+#: sequencer.c:817 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "Kann %s nicht öffnen: %s"
 
-#: sequencer.c:808
+#: sequencer.c:820
 #, c-format
 msgid "cannot read %s: %s"
 msgstr "Kann %s nicht lesen: %s"
 
-#: sequencer.c:809
+#: sequencer.c:821
 msgid "unexpected end of file"
 msgstr "Unerwartetes Dateiende"
 
-#: sequencer.c:815
+#: sequencer.c:827
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr ""
 "gespeicherte \"pre-cherry-pick\" Datei der Zweigspitze (HEAD) '%s' ist "
 "beschädigt"
 
-#: sequencer.c:838
+#: sequencer.c:850
 #, c-format
 msgid "Could not format %s."
 msgstr "Konnte %s nicht formatieren."
 
-#: sequencer.c:1000
+#: sequencer.c:1012
 msgid "Can't revert as initial commit"
 msgstr "Kann nicht zu initialer Version zurücksetzen."
 
-#: sequencer.c:1001
+#: sequencer.c:1013
 msgid "Can't cherry-pick into empty head"
 msgstr "Kann \"cherry-pick\" nicht in einem leerem Kopf ausführen."
 
@@ -926,12 +1031,17 @@ msgid "Upstream branch '%s' not stored as a remote-tracking branch"
 msgstr ""
 "Zweig '%s' des entfernten Projektarchivs ist kein gefolgter Übernahmezweig"
 
-#: wrapper.c:413
+#: wrapper.c:408
+#, c-format
+msgid "unable to access '%s': %s"
+msgstr "konnte nicht auf '%s' zugreifen: %s"
+
+#: wrapper.c:426
 #, c-format
 msgid "unable to look up current user in the passwd file: %s"
 msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s"
 
-#: wrapper.c:414
+#: wrapper.c:427
 msgid "no such user"
 msgstr "kein solcher Benutzer"
 
@@ -995,11 +1105,6 @@ msgstr ""
 "  (trage ein oder verwerfe den unbeobachteten oder geänderten Inhalt in den "
 "Unterprojekten)"
 
-#: wt-status.c:224
-#, c-format
-msgid "%s files:"
-msgstr "%s Dateien:"
-
 #: wt-status.c:227
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
@@ -1209,12 +1314,12 @@ msgid "Initial commit"
 msgstr "Initiale Version"
 
 #: wt-status.c:1011
-msgid "Untracked"
-msgstr "Unbeobachtete"
+msgid "Untracked files"
+msgstr "Unbeobachtete Dateien"
 
 #: wt-status.c:1013
-msgid "Ignored"
-msgstr "Ignorierte"
+msgid "Ignored files"
+msgstr "Ignorierte Dateien"
 
 #: wt-status.c:1015
 #, c-format
@@ -1229,59 +1334,73 @@ msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)"
 msgid "No changes"
 msgstr "Keine Änderungen"
 
-#: wt-status.c:1027
+#: wt-status.c:1028
 #, c-format
-msgid "no changes added to commit%s\n"
-msgstr "keine Änderungen zum Eintragen hinzugefügt%s\n"
-
-#: wt-status.c:1029
-msgid " (use \"git add\" and/or \"git commit -a\")"
-msgstr " (benutze \"git add\" und/oder \"git commit -a\")"
+msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+msgstr ""
+"keine Änderungen zum Eintragen hinzugefügt (benutze \"git add\" und/oder "
+"\"git commit -a\")\n"
 
 #: wt-status.c:1031
 #, c-format
-msgid "nothing added to commit but untracked files present%s\n"
+msgid "no changes added to commit\n"
+msgstr "keine Änderungen zum Eintragen hinzugefügt\n"
+
+#: wt-status.c:1034
+#, c-format
+msgid ""
+"nothing added to commit but untracked files present (use \"git add\" to "
+"track)\n"
 msgstr ""
-"nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien%s\n"
+"nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien "
+"(benutze \"git add\" zum Beobachten)\n"
 
-#: wt-status.c:1033
-msgid " (use \"git add\" to track)"
-msgstr " (benutze \"git add\" zum Beobachten)"
+#: wt-status.c:1037
+#, c-format
+msgid "nothing added to commit but untracked files present\n"
+msgstr "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien\n"
 
-#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041
+#: wt-status.c:1040
 #, c-format
-msgid "nothing to commit%s\n"
-msgstr "nichts zum Eintragen%s\n"
+msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
+msgstr ""
+"nichts einzutragen (Erstelle/Kopiere Dateien und benutze \"git add\" zum "
+"Beobachten)\n"
 
-#: wt-status.c:1036
-msgid " (create/copy files and use \"git add\" to track)"
-msgstr " (Erstelle/Kopiere Dateien und benutze \"git add\" zum Beobachten)"
+#: wt-status.c:1043 wt-status.c:1048
+#, c-format
+msgid "nothing to commit\n"
+msgstr "nichts einzutragen\n"
 
-#: wt-status.c:1039
-msgid " (use -u to show untracked files)"
-msgstr " (benutze die Option -u um unbeobachtete Dateien anzuzeigen)"
+#: wt-status.c:1046
+#, c-format
+msgid "nothing to commit (use -u to show untracked files)\n"
+msgstr ""
+"nichts einzutragen (benutze die Option -u, um unbeobachtete Dateien "
+"anzuzeigen)\n"
 
-#: wt-status.c:1042
-msgid " (working directory clean)"
-msgstr " (Arbeitsverzeichnis sauber)"
+#: wt-status.c:1050
+#, c-format
+msgid "nothing to commit, working directory clean\n"
+msgstr "nichts einzutragen, Arbeitsverzeichnis sauber\n"
 
-#: wt-status.c:1150
+#: wt-status.c:1158
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Zweig)"
 
-#: wt-status.c:1156
+#: wt-status.c:1164
 msgid "Initial commit on "
 msgstr "Initiale Version auf "
 
-#: wt-status.c:1171
+#: wt-status.c:1179
 msgid "behind "
 msgstr "hinterher "
 
-#: wt-status.c:1174 wt-status.c:1177
+#: wt-status.c:1182 wt-status.c:1185
 msgid "ahead "
 msgstr "voraus "
 
-#: wt-status.c:1179
+#: wt-status.c:1187
 msgid ", behind "
 msgstr ", hinterher "
 
@@ -1290,19 +1409,23 @@ msgstr ", hinterher "
 msgid "failed to unlink '%s'"
 msgstr "Konnte '%s' nicht entfernen"
 
+#: builtin/add.c:19
+msgid "git add [options] [--] <filepattern>..."
+msgstr "git add [Optionen] [--] [<Dateimuster>...]"
+
 #: builtin/add.c:62
 #, c-format
 msgid "unexpected diff status %c"
 msgstr "unerwarteter Differenz-Status %c"
 
-#: builtin/add.c:67 builtin/commit.c:229
+#: builtin/add.c:67 builtin/commit.c:231
 msgid "updating files failed"
 msgstr "Aktualisierung der Dateien fehlgeschlagen"
 
 #: builtin/add.c:77
 #, c-format
 msgid "remove '%s'\n"
-msgstr "entferne '%s'\n"
+msgstr "lösche '%s'\n"
 
 #: builtin/add.c:176
 #, c-format
@@ -1314,7 +1437,7 @@ msgid "Unstaged changes after refreshing the index:"
 msgstr ""
 "Nicht bereitgestellte Änderungen nach Aktualisierung der Bereitstellung:"
 
-#: builtin/add.c:195 builtin/add.c:459 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein"
@@ -1351,50 +1474,105 @@ msgstr "Leerer Patch. Abgebrochen."
 msgid "Could not apply '%s'"
 msgstr "Konnte '%s' nicht anwenden."
 
-#: builtin/add.c:312
+#: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
 msgstr ""
 "Die folgenden Pfade werden durch eine deiner \".gitignore\" Dateien "
 "ignoriert:\n"
 
-#: builtin/add.c:352
+#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
+#: builtin/rm.c:206
+msgid "dry run"
+msgstr "Probelauf"
+
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483
+#: builtin/mv.c:62 builtin/read-tree.c:112
+msgid "be verbose"
+msgstr "erweiterte Ausgaben"
+
+#: builtin/add.c:322
+msgid "interactive picking"
+msgstr "interaktives Auswählen"
+
+#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248
+msgid "select hunks interactively"
+msgstr "interaktiv Bereiche auswählen"
+
+#: builtin/add.c:324
+msgid "edit current diff and apply"
+msgstr "aktuelle Unterschiede editieren und anwenden"
+
+#: builtin/add.c:325
+msgid "allow adding otherwise ignored files"
+msgstr "erlaubt das Hinzufügen andernfalls ignorierter Dateien"
+
+#: builtin/add.c:326
+msgid "update tracked files"
+msgstr "aktualisiert beobachtete Dateien"
+
+#: builtin/add.c:327
+msgid "record only the fact that the path will be added later"
+msgstr "speichert nur, dass der Pfad später hinzugefügt werden soll"
+
+#: builtin/add.c:328
+msgid "add changes from all tracked and untracked files"
+msgstr ""
+"fügt Änderungen von allen beobachteten und unbeobachteten Dateien hinzu"
+
+#: builtin/add.c:329
+msgid "don't add, only refresh the index"
+msgstr "fügt nichts hinzu, aktualisiert nur die Bereitstellung"
+
+#: builtin/add.c:330
+msgid "just skip files which cannot be added because of errors"
+msgstr ""
+"überspringt Dateien, die aufgrund von Fehlern nicht hinzugefügt werden "
+"konnten"
+
+#: builtin/add.c:331
+msgid "check if - even missing - files are ignored in dry run"
+msgstr "prüft ob - auch fehlende - Dateien im Probelauf ignoriert werden"
+
+#: builtin/add.c:353
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr "Verwende -f wenn du diese wirklich hinzufügen möchtest.\n"
 
-#: builtin/add.c:353
+#: builtin/add.c:354
 msgid "no files added"
 msgstr "keine Dateien hinzugefügt"
 
-#: builtin/add.c:359
+#: builtin/add.c:360
 msgid "adding files failed"
 msgstr "Hinzufügen von Dateien fehlgeschlagen"
 
-#: builtin/add.c:391
+#: builtin/add.c:392
 msgid "-A and -u are mutually incompatible"
 msgstr "-A und -u sind zueinander inkompatibel"
 
-#: builtin/add.c:393
+#: builtin/add.c:394
 msgid "Option --ignore-missing can only be used together with --dry-run"
 msgstr ""
 "Die Option --ignore-missing kann nur zusammen mit --dry-run benutzt werden."
 
-#: builtin/add.c:413
+#: builtin/add.c:414
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
 
-#: builtin/add.c:414
+#: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "Wolltest du vielleicht 'git add .' sagen?\n"
 
-#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
-#: builtin/rm.c:162
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82
+#: builtin/rm.c:235
 msgid "index file corrupt"
 msgstr "Bereitstellungsdatei beschädigt"
 
-#: builtin/add.c:480 builtin/apply.c:4432 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370
 msgid "Unable to write new index file"
 msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
 
@@ -1451,17 +1629,17 @@ msgstr ""
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d"
 
-#: builtin/apply.c:1402
+#: builtin/apply.c:1420
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount: unerwartete Zeile: %.*s"
 
-#: builtin/apply.c:1459
+#: builtin/apply.c:1477
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
 msgstr "Patch-Fragment ohne Kopfbereich bei Zeile %d: %.*s"
 
-#: builtin/apply.c:1476
+#: builtin/apply.c:1494
 #, c-format
 msgid ""
 "git diff header lacks filename information when removing %d leading pathname "
@@ -1476,70 +1654,70 @@ msgstr[1] ""
 "Dem Kopfbereich von \"git diff\" fehlen Informationen zum Dateinamen, wenn "
 "%d vorangestellte Teile des Pfades entfernt werden (Zeile %d)"
 
-#: builtin/apply.c:1636
+#: builtin/apply.c:1654
 msgid "new file depends on old contents"
 msgstr "neue Datei hängt von alten Inhalten ab"
 
-#: builtin/apply.c:1638
+#: builtin/apply.c:1656
 msgid "deleted file still has contents"
 msgstr "entfernte Datei hat noch Inhalte"
 
-#: builtin/apply.c:1664
+#: builtin/apply.c:1682
 #, c-format
 msgid "corrupt patch at line %d"
 msgstr "fehlerhafter Patch bei Zeile %d"
 
-#: builtin/apply.c:1700
+#: builtin/apply.c:1718
 #, c-format
 msgid "new file %s depends on old contents"
 msgstr "neue Datei %s hängt von alten Inhalten ab"
 
-#: builtin/apply.c:1702
+#: builtin/apply.c:1720
 #, c-format
 msgid "deleted file %s still has contents"
 msgstr "entfernte Datei %s hat noch Inhalte"
 
-#: builtin/apply.c:1705
+#: builtin/apply.c:1723
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
 msgstr "** Warnung: Datei %s wird leer, aber nicht entfernt."
 
-#: builtin/apply.c:1851
+#: builtin/apply.c:1869
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
 msgstr "fehlerhafter Binär-Patch bei Zeile %d: %.*s"
 
 #. there has to be one hunk (forward hunk)
-#: builtin/apply.c:1880
+#: builtin/apply.c:1898
 #, c-format
 msgid "unrecognized binary patch at line %d"
 msgstr "nicht erkannter Binär-Patch bei Zeile %d"
 
-#: builtin/apply.c:1966
+#: builtin/apply.c:1984
 #, c-format
 msgid "patch with only garbage at line %d"
 msgstr "Patch mit nutzlosen Informationen bei Zeile %d"
 
-#: builtin/apply.c:2056
+#: builtin/apply.c:2074
 #, c-format
 msgid "unable to read symlink %s"
 msgstr "konnte symbolische Verknüpfung %s nicht lesen"
 
-#: builtin/apply.c:2060
+#: builtin/apply.c:2078
 #, c-format
 msgid "unable to open or read %s"
 msgstr "konnte %s nicht öffnen oder lesen"
 
-#: builtin/apply.c:2131
+#: builtin/apply.c:2149
 msgid "oops"
 msgstr "Ups"
 
-#: builtin/apply.c:2653
+#: builtin/apply.c:2671
 #, c-format
 msgid "invalid start of line: '%c'"
 msgstr "Ungültiger Zeilenanfang: '%c'"
 
-#: builtin/apply.c:2771
+#: builtin/apply.c:2789
 #, c-format
 msgid "Hunk #%d succeeded at %d (offset %d line)."
 msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
@@ -1547,12 +1725,12 @@ msgstr[0] "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeile versetzt)"
 msgstr[1] ""
 "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeilen versetzt)"
 
-#: builtin/apply.c:2783
+#: builtin/apply.c:2801
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
 msgstr "Kontext reduziert zu (%ld/%ld) um Patch-Bereich bei %d anzuwenden"
 
-#: builtin/apply.c:2789
+#: builtin/apply.c:2807
 #, c-format
 msgid ""
 "while searching for:\n"
@@ -1561,339 +1739,335 @@ msgstr ""
 "bei der Suche nach:\n"
 "%.*s"
 
-#: builtin/apply.c:2808
+#: builtin/apply.c:2826
 #, c-format
 msgid "missing binary patch data for '%s'"
 msgstr "keine Daten in Binär-Patch für '%s'"
 
-#: builtin/apply.c:2911
+#: builtin/apply.c:2929
 #, c-format
 msgid "binary patch does not apply to '%s'"
 msgstr "Konnte Binär-Patch nicht auf '%s' anwenden"
 
-#: builtin/apply.c:2917
+#: builtin/apply.c:2935
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
 msgstr ""
 "Binär-Patch für '%s' erzeugt falsches Ergebnis (erwartete %s, bekam %s)"
 
-#: builtin/apply.c:2938
+#: builtin/apply.c:2956
 #, c-format
 msgid "patch failed: %s:%ld"
 msgstr "Anwendung des Patches fehlgeschlagen: %s:%ld"
 
-#: builtin/apply.c:3060
+#: builtin/apply.c:3078
 #, c-format
 msgid "cannot checkout %s"
 msgstr "kann %s nicht auschecken"
 
-#: builtin/apply.c:3105 builtin/apply.c:3114 builtin/apply.c:3158
+#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176
 #, c-format
 msgid "read of %s failed"
 msgstr "Konnte %s nicht lesen"
 
-#: builtin/apply.c:3138 builtin/apply.c:3360
+#: builtin/apply.c:3156 builtin/apply.c:3378
 #, c-format
 msgid "path %s has been renamed/deleted"
 msgstr "Pfad %s wurde umbenannt/gelöscht"
 
-#: builtin/apply.c:3219 builtin/apply.c:3374
+#: builtin/apply.c:3237 builtin/apply.c:3392
 #, c-format
 msgid "%s: does not exist in index"
 msgstr "%s ist nicht bereitgestellt"
 
-#: builtin/apply.c:3223 builtin/apply.c:3366 builtin/apply.c:3388
+#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406
 #, c-format
 msgid "%s: %s"
 msgstr "%s: %s"
 
-#: builtin/apply.c:3228 builtin/apply.c:3382
+#: builtin/apply.c:3246 builtin/apply.c:3400
 #, c-format
 msgid "%s: does not match index"
 msgstr "%s entspricht nicht der Bereitstellung"
 
-#: builtin/apply.c:3330
+#: builtin/apply.c:3348
 msgid "removal patch leaves file contents"
 msgstr "Lösch-Patch hinterlässt Dateiinhalte"
 
-#: builtin/apply.c:3399
+#: builtin/apply.c:3417
 #, c-format
 msgid "%s: wrong type"
 msgstr "%s: falscher Typ"
 
-#: builtin/apply.c:3401
+#: builtin/apply.c:3419
 #, c-format
 msgid "%s has type %o, expected %o"
 msgstr "%s ist vom Typ %o, erwartete %o"
 
-#: builtin/apply.c:3502
+#: builtin/apply.c:3520
 #, c-format
 msgid "%s: already exists in index"
 msgstr "%s ist bereits bereitgestellt"
 
-#: builtin/apply.c:3505
+#: builtin/apply.c:3523
 #, c-format
 msgid "%s: already exists in working directory"
 msgstr "%s existiert bereits im Arbeitsverzeichnis"
 
-#: builtin/apply.c:3525
+#: builtin/apply.c:3543
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o)"
 msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o)"
 
-#: builtin/apply.c:3530
+#: builtin/apply.c:3548
 #, c-format
 msgid "new mode (%o) of %s does not match old mode (%o) of %s"
 msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o) von %s"
 
-#: builtin/apply.c:3538
+#: builtin/apply.c:3556
 #, c-format
 msgid "%s: patch does not apply"
 msgstr "%s: Patch konnte nicht angewendet werden"
 
-#: builtin/apply.c:3551
+#: builtin/apply.c:3569
 #, c-format
 msgid "Checking patch %s..."
 msgstr "Prüfe Patch %s..."
 
-#: builtin/apply.c:3606 builtin/checkout.c:213 builtin/reset.c:158
+#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158
 #, c-format
 msgid "make_cache_entry failed for path '%s'"
 msgstr "make_cache_entry für Pfad '%s' fehlgeschlagen"
 
-#: builtin/apply.c:3749
+#: builtin/apply.c:3767
 #, c-format
 msgid "unable to remove %s from index"
 msgstr "konnte %s nicht aus der Bereitstellung entfernen"
 
-#: builtin/apply.c:3777
+#: builtin/apply.c:3795
 #, c-format
 msgid "corrupt patch for subproject %s"
 msgstr "fehlerhafter Patch für Unterprojekt %s"
 
-#: builtin/apply.c:3781
+#: builtin/apply.c:3799
 #, c-format
 msgid "unable to stat newly created file '%s'"
 msgstr "konnte neu erstellte Datei '%s' nicht lesen"
 
-#: builtin/apply.c:3786
+#: builtin/apply.c:3804
 #, c-format
 msgid "unable to create backing store for newly created file %s"
 msgstr "kann internen Speicher für eben erstellte Datei %s nicht erzeugen"
 
-#: builtin/apply.c:3789 builtin/apply.c:3897
+#: builtin/apply.c:3807 builtin/apply.c:3915
 #, c-format
 msgid "unable to add cache entry for %s"
 msgstr "kann für %s keinen Eintrag in den Zwischenspeicher hinzufügen"
 
-#: builtin/apply.c:3822
+#: builtin/apply.c:3840
 #, c-format
 msgid "closing file '%s'"
 msgstr "schließe Datei '%s'"
 
-#: builtin/apply.c:3871
+#: builtin/apply.c:3889
 #, c-format
 msgid "unable to write file '%s' mode %o"
 msgstr "konnte Datei '%s' mit Modus %o nicht schreiben"
 
-#: builtin/apply.c:3958
+#: builtin/apply.c:3976
 #, c-format
 msgid "Applied patch %s cleanly."
 msgstr "Patch %s sauber angewendet"
 
-#: builtin/apply.c:3966
+#: builtin/apply.c:3984
 msgid "internal error"
 msgstr "interner Fehler"
 
 #. Say this even without --verbose
-#: builtin/apply.c:3969
+#: builtin/apply.c:3987
 #, c-format
 msgid "Applying patch %%s with %d reject..."
 msgid_plural "Applying patch %%s with %d rejects..."
 msgstr[0] "Wende Patch %%s mit %d Zurückweisung an..."
 msgstr[1] "Wende Patch %%s mit %d Zurückweisungen an..."
 
-#: builtin/apply.c:3979
+#: builtin/apply.c:3997
 #, c-format
 msgid "truncating .rej filename to %.*s.rej"
 msgstr "Verkürze Name von .rej Datei zu %.*s.rej"
 
-#: builtin/apply.c:4000
+#: builtin/apply.c:4018
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Patch-Bereich #%d sauber angewendet."
 
-#: builtin/apply.c:4003
+#: builtin/apply.c:4021
 #, c-format
 msgid "Rejected hunk #%d."
 msgstr "Patch-Bereich #%d zurückgewiesen."
 
-#: builtin/apply.c:4153
+#: builtin/apply.c:4171
 msgid "unrecognized input"
 msgstr "nicht erkannte Eingabe"
 
-#: builtin/apply.c:4164
+#: builtin/apply.c:4182
 msgid "unable to read index file"
 msgstr "Konnte Bereitstellungsdatei nicht lesen"
 
-#: builtin/apply.c:4283 builtin/apply.c:4286
+#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91
+#: builtin/fetch.c:63
 msgid "path"
 msgstr "Pfad"
 
-#: builtin/apply.c:4284
+#: builtin/apply.c:4302
 msgid "don't apply changes matching the given path"
 msgstr "wendet keine Änderungen im angegebenen Pfad an"
 
-#: builtin/apply.c:4287
+#: builtin/apply.c:4305
 msgid "apply changes matching the given path"
 msgstr "wendet Änderungen nur im angegebenen Pfad an"
 
-#: builtin/apply.c:4289
+#: builtin/apply.c:4307
 msgid "num"
 msgstr "Anzahl"
 
-#: builtin/apply.c:4290
+#: builtin/apply.c:4308
 msgid "remove <num> leading slashes from traditional diff paths"
 msgstr ""
 "entfernt <Anzahl> vorangestellte Schrägstriche von herkömmlichen "
 "Differenzpfaden"
 
-#: builtin/apply.c:4293
+#: builtin/apply.c:4311
 msgid "ignore additions made by the patch"
 msgstr "ignoriert hinzugefügte Zeilen des Patches"
 
-#: builtin/apply.c:4295
+#: builtin/apply.c:4313
 msgid "instead of applying the patch, output diffstat for the input"
 msgstr ""
 "anstatt der Anwendung des Patches, wird der \"diffstat\" für die Eingabe "
 "ausgegeben"
 
-#: builtin/apply.c:4299
-msgid "shows number of added and deleted lines in decimal notation"
+#: builtin/apply.c:4317
+msgid "show number of added and deleted lines in decimal notation"
 msgstr ""
 "zeigt die Anzahl von hinzugefügten/entfernten Zeilen in Dezimalnotation"
 
-#: builtin/apply.c:4301
+#: builtin/apply.c:4319
 msgid "instead of applying the patch, output a summary for the input"
 msgstr ""
 "anstatt der Anwendung des Patches, wird eine Zusammenfassung für die Eingabe "
 "ausgegeben"
 
-#: builtin/apply.c:4303
+#: builtin/apply.c:4321
 msgid "instead of applying the patch, see if the patch is applicable"
 msgstr ""
 "anstatt der Anwendung des Patches, zeige ob Patch angewendet werden kann"
 
-#: builtin/apply.c:4305
+#: builtin/apply.c:4323
 msgid "make sure the patch is applicable to the current index"
 msgstr ""
 "stellt sicher, dass der Patch in der aktuellen Bereitstellung angewendet "
 "werden kann"
 
-#: builtin/apply.c:4307
+#: builtin/apply.c:4325
 msgid "apply a patch without touching the working tree"
 msgstr "wendet einen Patch an, ohne Änderungen im Arbeitszweig vorzunehmen"
 
-#: builtin/apply.c:4309
+#: builtin/apply.c:4327
 msgid "also apply the patch (use with --stat/--summary/--check)"
 msgstr "wendet den Patch an (Benutzung mit --stat/--summary/--check)"
 
-#: builtin/apply.c:4311
+#: builtin/apply.c:4329
 msgid "attempt three-way merge if a patch does not apply"
 msgstr ""
 "versucht 3-Wege-Zusammenführung, wenn der Patch nicht angewendet werden "
 "konnte"
 
-#: builtin/apply.c:4313
+#: builtin/apply.c:4331
 msgid "build a temporary index based on embedded index information"
 msgstr ""
 "erstellt eine temporäre Bereitstellung basierend auf den integrierten "
 "Bereitstellungsinformationen"
 
-#: builtin/apply.c:4315
+#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460
 msgid "paths are separated with NUL character"
 msgstr "Pfade sind getrennt durch NUL Zeichen"
 
-#: builtin/apply.c:4318
+#: builtin/apply.c:4336
 msgid "ensure at least <n> lines of context match"
-msgstr ""
-"stellt sicher, dass mindestens <Anzahl> Zeilen des Kontextes übereinstimmen"
+msgstr "stellt sicher, dass mindestens <n> Zeilen des Kontextes übereinstimmen"
 
-#: builtin/apply.c:4319
+#: builtin/apply.c:4337
 msgid "action"
 msgstr "Aktion"
 
-#: builtin/apply.c:4320
+#: builtin/apply.c:4338
 msgid "detect new or modified lines that have whitespace errors"
 msgstr "ermittelt neue oder geänderte Zeilen die Fehler in Leerzeichen haben"
 
-#: builtin/apply.c:4323 builtin/apply.c:4326
+#: builtin/apply.c:4341 builtin/apply.c:4344
 msgid "ignore changes in whitespace when finding context"
 msgstr "ignoriert Änderungen in Leerzeichen bei der Suche des Kontextes"
 
-#: builtin/apply.c:4329
+#: builtin/apply.c:4347
 msgid "apply the patch in reverse"
 msgstr "wendet den Patch in umgekehrter Reihenfolge an"
 
-#: builtin/apply.c:4331
+#: builtin/apply.c:4349
 msgid "don't expect at least one line of context"
 msgstr "erwartet keinen Kontext"
 
-#: builtin/apply.c:4333
+#: builtin/apply.c:4351
 msgid "leave the rejected hunks in corresponding *.rej files"
 msgstr ""
 "hinterlässt zurückgewiesene Patch-Bereiche in den entsprechenden *.rej "
 "Dateien"
 
-#: builtin/apply.c:4335
+#: builtin/apply.c:4353
 msgid "allow overlapping hunks"
 msgstr "erlaubt sich überlappende Patch-Bereiche"
 
-#: builtin/apply.c:4336
-msgid "be verbose"
-msgstr "erweiterte Ausgaben"
-
-#: builtin/apply.c:4338
+#: builtin/apply.c:4356
 msgid "tolerate incorrectly detected missing new-line at the end of file"
 msgstr "toleriert fehlerhaft erkannten fehlenden Zeilenumbruch am Dateiende"
 
-#: builtin/apply.c:4341
+#: builtin/apply.c:4359
 msgid "do not trust the line counts in the hunk headers"
 msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Bereiches"
 
-#: builtin/apply.c:4343
+#: builtin/apply.c:4361
 msgid "root"
 msgstr "Wurzelverzeichnis"
 
-#: builtin/apply.c:4344
+#: builtin/apply.c:4362
 msgid "prepend <root> to all filenames"
 msgstr "stellt <Wurzelverzeichnis> vor alle Dateinamen"
 
-#: builtin/apply.c:4366
+#: builtin/apply.c:4384
 msgid "--3way outside a repository"
 msgstr "--3way außerhalb eines Projektarchivs"
 
-#: builtin/apply.c:4374
+#: builtin/apply.c:4392
 msgid "--index outside a repository"
 msgstr "--index außerhalb eines Projektarchivs"
 
-#: builtin/apply.c:4377
+#: builtin/apply.c:4395
 msgid "--cached outside a repository"
 msgstr "--cached außerhalb eines Projektarchivs"
 
-#: builtin/apply.c:4393
+#: builtin/apply.c:4411
 #, c-format
 msgid "can't open patch '%s'"
 msgstr "kann Patch '%s' nicht öffnen"
 
-#: builtin/apply.c:4407
+#: builtin/apply.c:4425
 #, c-format
 msgid "squelched %d whitespace error"
 msgid_plural "squelched %d whitespace errors"
 msgstr[0] "unterdrückte %d Fehler in Leerzeichen"
 msgstr[1] "unterdrückte %d Fehler in Leerzeichen"
 
-#: builtin/apply.c:4413 builtin/apply.c:4423
+#: builtin/apply.c:4431 builtin/apply.c:4441
 #, c-format
 msgid "%d line adds whitespace errors."
 msgid_plural "%d lines add whitespace errors."
@@ -1935,7 +2109,136 @@ msgstr "git archive: Protokollfehler"
 msgid "git archive: expected a flush"
 msgstr "git archive: erwartete eine Spülung (flush)"
 
-#: builtin/branch.c:144
+#: builtin/bisect--helper.c:7
+msgid "git bisect--helper --next-all [--no-checkout]"
+msgstr "git bisect--helper --next-all [--no-checkout]"
+
+#: builtin/bisect--helper.c:17
+msgid "perform 'git bisect next'"
+msgstr "führt 'git bisect next' aus"
+
+#: builtin/bisect--helper.c:19
+msgid "update BISECT_HEAD instead of checking out the current commit"
+msgstr "aktualisiert BISECT_HEAD, anstatt die aktuelle Version auszuchecken"
+
+#: builtin/blame.c:25
+msgid "git blame [options] [rev-opts] [rev] [--] file"
+msgstr "git blame [Optionen] [rev-opts] [rev] [--] Datei"
+
+#: builtin/blame.c:30 builtin/shortlog.c:15
+msgid "[rev-opts] are documented in git-rev-list(1)"
+msgstr "[rev-opts] sind dokumentiert in git-rev-list(1)"
+
+#: builtin/blame.c:2374
+msgid "Show blame entries as we find them, incrementally"
+msgstr "Zeigt \"blame\"-Einträge schrittweise, während wir sie generieren"
+
+#: builtin/blame.c:2375
+msgid "Show blank SHA-1 for boundary commits (Default: off)"
+msgstr "Zeigt leere SHA-1 für Grenzversionen (Standard: aus)"
+
+#: builtin/blame.c:2376
+msgid "Do not treat root commits as boundaries (Default: off)"
+msgstr "Behandelt Ursprungsversionen nicht als Grenzen (Standard: aus)"
+
+#: builtin/blame.c:2377
+msgid "Show work cost statistics"
+msgstr "Zeigt Statistiken zum Arbeitsaufwand"
+
+#: builtin/blame.c:2378
+msgid "Show output score for blame entries"
+msgstr "Zeigt Ausgabebewertung für \"blame\"-Einträge"
+
+#: builtin/blame.c:2379
+msgid "Show original filename (Default: auto)"
+msgstr "Zeigt ursprünglichen Dateinamen (Standard: auto)"
+
+#: builtin/blame.c:2380
+msgid "Show original linenumber (Default: off)"
+msgstr "Zeigt ursprüngliche Zeilennummer (Standard: aus)"
+
+#: builtin/blame.c:2381
+msgid "Show in a format designed for machine consumption"
+msgstr "Anzeige in einem Format für maschinelle Auswertung"
+
+#: builtin/blame.c:2382
+msgid "Show porcelain format with per-line commit information"
+msgstr ""
+"Anzeige in Format für Fremdprogramme mit Versionsinformationen pro Zeile"
+
+#: builtin/blame.c:2383
+msgid "Use the same output mode as git-annotate (Default: off)"
+msgstr "Benutzt den gleichen Ausgabemodus wie \"git-annotate\" (Standard: aus)"
+
+#: builtin/blame.c:2384
+msgid "Show raw timestamp (Default: off)"
+msgstr "Zeigt unbearbeiteten Zeitstempel (Standard: aus)"
+
+#: builtin/blame.c:2385
+msgid "Show long commit SHA1 (Default: off)"
+msgstr "Zeigt langen Versions-SHA1 (Standard: aus)"
+
+#: builtin/blame.c:2386
+msgid "Suppress author name and timestamp (Default: off)"
+msgstr "Unterdrückt den Namen des Autors und den Zeitstempel (Standard: aus)"
+
+#: builtin/blame.c:2387
+msgid "Show author email instead of name (Default: off)"
+msgstr "Zeigt anstatt des Namens die Email-Adresse des Autors (Standard: aus)"
+
+#: builtin/blame.c:2388
+msgid "Ignore whitespace differences"
+msgstr "Ignoriert Unterschiede in Leerzeichen"
+
+#: builtin/blame.c:2389
+msgid "Spend extra cycles to find better match"
+msgstr "arbeite länger, um bessere Übereinstimmungen zu finden"
+
+#: builtin/blame.c:2390
+msgid "Use revisions from <file> instead of calling git-rev-list"
+msgstr "Benutzt Revisionen von <Datei> anstatt \"git-rev-list\" aufzurufen"
+
+#: builtin/blame.c:2391
+msgid "Use <file>'s contents as the final image"
+msgstr "Benutzt Inhalte der <Datei>en als entgültiges Abbild"
+
+#: builtin/blame.c:2392 builtin/blame.c:2393
+msgid "score"
+msgstr "Bewertung"
+
+#: builtin/blame.c:2392
+msgid "Find line copies within and across files"
+msgstr "Findet kopierte Zeilen innerhalb oder zwischen Dateien"
+
+#: builtin/blame.c:2393
+msgid "Find line movements within and across files"
+msgstr "Findet verschobene Zeilen innerhalb oder zwischen Dateien"
+
+#: builtin/blame.c:2394
+msgid "n,m"
+msgstr "n,m"
+
+#: builtin/blame.c:2394
+msgid "Process only line range n,m, counting from 1"
+msgstr "Verarbeitet nur Zeilen im Bereich n,m, gezählt von 1"
+
+#: builtin/branch.c:23
+msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
+msgstr "git branch [Optionen] [-r | -a] [--merged | --no-merged]"
+
+#: builtin/branch.c:24
+msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
+msgstr "git branch [Optionen] [-l] [-f] <Zweigname> [<Startpunkt>]"
+
+#: builtin/branch.c:25
+msgid "git branch [options] [-r] (-d | -D) <branchname>..."
+msgstr "git branch [Optionen] [-r] (-d | -D) <Zweigname>..."
+
+#: builtin/branch.c:26
+msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
+msgstr "git branch [Optionen] (-m | -M) [<alterZweig>] <neuerZweig>"
+
+#: builtin/branch.c:145
 #, c-format
 msgid ""
 "deleting branch '%s' that has been merged to\n"
@@ -1945,7 +2248,7 @@ msgstr ""
 "         '%s', aber noch nicht mit der Zweigspitze (HEAD) zusammengeführt "
 "wurde."
 
-#: builtin/branch.c:148
+#: builtin/branch.c:149
 #, c-format
 msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
@@ -1954,169 +2257,300 @@ msgstr ""
 "entferne Zweig '%s' nicht, der noch nicht zusammengeführt wurde mit\n"
 "         '%s', obwohl er mit der Zweigspitze (HEAD) zusammengeführt wurde."
 
+#: builtin/branch.c:163
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "Konnte Versionsobjekt für '%s' nicht nachschlagen."
+
+#: builtin/branch.c:167
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+"Der Zweig '%s' ist nicht vollständig zusammengeführt.\n"
+"Wenn du sicher bist diesen Zweig zu entfernen, führe 'git branch -D %s' aus."
+
 #: builtin/branch.c:180
+msgid "Update of config-file failed"
+msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen."
+
+#: builtin/branch.c:208
 msgid "cannot use -a with -d"
 msgstr "kann -a nicht mit -d benutzen"
 
-#: builtin/branch.c:186
+#: builtin/branch.c:214
 msgid "Couldn't look up commit object for HEAD"
 msgstr "Konnte Versionsobjekt für Zweigspitze (HEAD) nicht nachschlagen."
 
-#: builtin/branch.c:191
+#: builtin/branch.c:222
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
 msgstr ""
 "Kann Zweig '%s' nicht entfernen, da du dich gerade auf diesem befindest."
 
-#: builtin/branch.c:202
+#: builtin/branch.c:235
 #, c-format
 msgid "remote branch '%s' not found."
 msgstr "externer Zweig '%s' nicht gefunden"
 
-#: builtin/branch.c:203
+#: builtin/branch.c:236
 #, c-format
 msgid "branch '%s' not found."
 msgstr "Zweig '%s' nicht gefunden."
 
-#: builtin/branch.c:210
-#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Konnte Versionsobjekt für '%s' nicht nachschlagen."
-
-#: builtin/branch.c:216
-#, c-format
-msgid ""
-"The branch '%s' is not fully merged.\n"
-"If you are sure you want to delete it, run 'git branch -D %s'."
-msgstr ""
-"Der Zweig '%s' ist nicht vollständig zusammengeführt.\n"
-"Wenn du sicher bist diesen Zweig zu entfernen, führe 'git branch -D %s' aus."
-
-#: builtin/branch.c:225
+#: builtin/branch.c:250
 #, c-format
 msgid "Error deleting remote branch '%s'"
 msgstr "Fehler beim Entfernen des externen Zweiges '%s'"
 
-#: builtin/branch.c:226
+#: builtin/branch.c:251
 #, c-format
 msgid "Error deleting branch '%s'"
 msgstr "Fehler beim Entfernen des Zweiges '%s'"
 
-#: builtin/branch.c:233
+#: builtin/branch.c:258
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr "Externer Zweig %s entfernt (war %s).\n"
 
-#: builtin/branch.c:234
+#: builtin/branch.c:259
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr "Zweig %s entfernt (war %s).\n"
 
-#: builtin/branch.c:239
-msgid "Update of config-file failed"
-msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen."
-
-#: builtin/branch.c:337
+#: builtin/branch.c:361
 #, c-format
 msgid "branch '%s' does not point at a commit"
 msgstr "Zweig '%s' zeigt auf keine Version"
 
-#: builtin/branch.c:409
+#: builtin/branch.c:433
 #, c-format
 msgid "[%s: behind %d]"
 msgstr "[%s: %d hinterher]"
 
-#: builtin/branch.c:411
+#: builtin/branch.c:435
 #, c-format
 msgid "[behind %d]"
 msgstr "[%d hinterher]"
 
-#: builtin/branch.c:415
+#: builtin/branch.c:439
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr "[%s: %d voraus]"
 
-#: builtin/branch.c:417
+#: builtin/branch.c:441
 #, c-format
 msgid "[ahead %d]"
 msgstr "[%d voraus]"
 
-#: builtin/branch.c:420
+#: builtin/branch.c:444
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr "[%s: %d voraus, %d hinterher]"
 
-#: builtin/branch.c:423
+#: builtin/branch.c:447
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr "[%d voraus, %d hinterher]"
 
-#: builtin/branch.c:535
+#: builtin/branch.c:560
 msgid "(no branch)"
 msgstr "(kein Zweig)"
 
-#: builtin/branch.c:600
+#: builtin/branch.c:625
 msgid "some refs could not be read"
 msgstr "Konnte einige Referenzen nicht lesen"
 
-#: builtin/branch.c:613
+#: builtin/branch.c:638
 msgid "cannot rename the current branch while not on any."
 msgstr ""
 "Kann aktuellen Zweig nicht umbenennen, solange du dich auf keinem befindest."
 
-#: builtin/branch.c:623
+#: builtin/branch.c:648
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Ungültiger Zweig-Name: '%s'"
 
-#: builtin/branch.c:638
+#: builtin/branch.c:663
 msgid "Branch rename failed"
 msgstr "Umbenennung des Zweiges fehlgeschlagen"
 
-#: builtin/branch.c:642
+#: builtin/branch.c:667
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
 msgstr "falsch benannten Zweig '%s' umbenannt"
 
-#: builtin/branch.c:646
+#: builtin/branch.c:671
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr "Zweig umbenannt zu %s, aber Zweigspitze (HEAD) ist nicht aktualisiert!"
 
-#: builtin/branch.c:653
+#: builtin/branch.c:678
 msgid "Branch is renamed, but update of config-file failed"
 msgstr ""
 "Zweig ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
 "fehlgeschlagen."
 
-#: builtin/branch.c:668
+#: builtin/branch.c:693
 #, c-format
 msgid "malformed object name %s"
 msgstr "Missgebildeter Objektname %s"
 
-#: builtin/branch.c:692
+#: builtin/branch.c:717
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s"
 
-#: builtin/branch.c:783
+#: builtin/branch.c:747
+msgid "Generic options"
+msgstr "Allgemeine Optionen"
+
+#: builtin/branch.c:749
+msgid "show hash and subject, give twice for upstream branch"
+msgstr "Zeigt Hash und Betreff; -vv: zusätzlich externen Übernahmezweig"
+
+#: builtin/branch.c:750
+msgid "suppress informational messages"
+msgstr "unterdrückt Informationsmeldungen"
+
+#: builtin/branch.c:751
+msgid "set up tracking mode (see git-pull(1))"
+msgstr "stellt den Übernahmemodus ein (siehe git-pull(1))"
+
+#: builtin/branch.c:753
+msgid "change upstream info"
+msgstr "ändert Informationen zum externen Übernahmezweig"
+
+#: builtin/branch.c:757
+msgid "use colored output"
+msgstr "verwendet farbliche Ausgaben"
+
+#: builtin/branch.c:758
+msgid "act on remote-tracking branches"
+msgstr "wirkt auf externe Übernahmezweige"
+
+#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
+#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377
+#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470
+msgid "commit"
+msgstr "Version"
+
+#: builtin/branch.c:762 builtin/branch.c:768
+msgid "print only branches that contain the commit"
+msgstr "gibt nur Zweige aus, welche diese Version beinhalten"
+
+#: builtin/branch.c:774
+msgid "Specific git-branch actions:"
+msgstr "spezifische Aktionen für \"git-branch\":"
+
+#: builtin/branch.c:775
+msgid "list both remote-tracking and local branches"
+msgstr "listet externe Übernahmezweige und lokale Zweige auf"
+
+#: builtin/branch.c:777
+msgid "delete fully merged branch"
+msgstr "entfernt vollständig zusammengeführten Zweig"
+
+#: builtin/branch.c:778
+msgid "delete branch (even if not merged)"
+msgstr "löscht Zweig (auch wenn nicht zusammengeführt)"
+
+#: builtin/branch.c:779
+msgid "move/rename a branch and its reflog"
+msgstr "verschiebt/benennt einen Zweig und dessen Referenzprotokoll um"
+
+#: builtin/branch.c:780
+msgid "move/rename a branch, even if target exists"
+msgstr ""
+"verschiebt/benennt einen Zweig um, auch wenn das Ziel bereits existiert"
+
+#: builtin/branch.c:781
+msgid "list branch names"
+msgstr "listet Zweignamen auf"
+
+#: builtin/branch.c:782
+msgid "create the branch's reflog"
+msgstr "erzeugt das Referenzprotokoll des Zweiges"
+
+#: builtin/branch.c:784
+msgid "edit the description for the branch"
+msgstr "bearbeitet die Beschreibung für den Zweig"
+
+#: builtin/branch.c:785
+msgid "force creation (when already exists)"
+msgstr "erzeuge auch, wenn der Zweig bereits existiert"
+
+#: builtin/branch.c:788
+msgid "print only not merged branches"
+msgstr "gibt nur Zweige aus, die nicht zusammengeführt sind"
+
+#: builtin/branch.c:794
+msgid "print only merged branches"
+msgstr "gibt nur Zweige aus, die zusammengeführt sind"
+
+#: builtin/branch.c:798
+msgid "list branches in columns"
+msgstr "listet Zweige in Spalten auf"
+
+#: builtin/branch.c:811
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "Konnte Zweigspitze (HEAD) nicht als gültige Referenz auflösen."
 
-#: builtin/branch.c:788 builtin/clone.c:561
+#: builtin/branch.c:816 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!"
 
-#: builtin/branch.c:808
+#: builtin/branch.c:836
 msgid "--column and --verbose are incompatible"
 msgstr "--column und --verbose sind inkompatibel"
 
-#: builtin/branch.c:857
+#: builtin/branch.c:887
+#, c-format
+msgid "branch '%s' does not exist"
+msgstr "Zweig '%s' existiert nicht"
+
+#: builtin/branch.c:899
+#, c-format
+msgid "Branch '%s' has no upstream information"
+msgstr "Zweig '%s' hat keinen externen Übernahmezweig gesetzt"
+
+#: builtin/branch.c:914
 msgid "-a and -r options to 'git branch' do not make sense with a branch name"
 msgstr ""
 "Die Optionen -a und -r bei 'git branch' machen mit einem Zweignamen keinen "
 "Sinn."
 
+#: builtin/branch.c:917
+#, c-format
+msgid ""
+"The --set-upstream flag is deprecated and will be removed. Consider using --"
+"track or --set-upstream-to\n"
+msgstr ""
+"Die --set-upstream Option ist veraltet und wird entfernt. Benutze --track "
+"oder --set-upstream-to\n"
+
+#: builtin/branch.c:934
+#, c-format
+msgid ""
+"\n"
+"If you wanted to make '%s' track '%s', do this:\n"
+"\n"
+msgstr ""
+"\n"
+"Wenn du wolltest, dass '%s' den Zweig '%s' als externen Übernahmezweig hat, "
+"führe aus:\n"
+
+#: builtin/branch.c:935
+#, c-format
+msgid "    git branch -d %s\n"
+msgstr "    git branch -d %s\n"
+
+#: builtin/branch.c:936
+#, c-format
+msgid "    git branch --set-upstream-to %s\n"
+msgstr "    git branch --set-upstream-to %s\n"
+
 #: builtin/bundle.c:47
 #, c-format
 msgid "%s is okay\n"
@@ -2130,95 +2564,228 @@ msgstr "Um ein Paket zu erstellen wird ein Projektarchiv benötigt."
 msgid "Need a repository to unbundle."
 msgstr "Zum Entpacken wird ein Projektarchiv benötigt."
 
-#: builtin/checkout.c:114 builtin/checkout.c:147
-#, c-format
-msgid "path '%s' does not have our version"
-msgstr "Pfad '%s' hat nicht unsere Version."
+#: builtin/cat-file.c:247
+msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
+msgstr "git cat-file (-t|-s|-e|-p|<Art>|--textconv) <Objekt>"
 
-#: builtin/checkout.c:116 builtin/checkout.c:149
-#, c-format
-msgid "path '%s' does not have their version"
-msgstr "Pfad '%s' hat nicht deren Version."
+#: builtin/cat-file.c:248
+msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
+msgstr "git cat-file (--batch|--batch-check) < <Liste_von_Objekten>"
 
-#: builtin/checkout.c:132
-#, c-format
-msgid "path '%s' does not have all necessary versions"
-msgstr "Pfad '%s' hat nicht alle notwendigen Versionen."
+#: builtin/cat-file.c:266
+msgid "<type> can be one of: blob, tree, commit, tag"
+msgstr "<Art> kann sein: blob, tree, commit, tag"
 
-#: builtin/checkout.c:176
-#, c-format
-msgid "path '%s' does not have necessary versions"
-msgstr "Pfad '%s' hat nicht die notwendigen Versionen."
+#: builtin/cat-file.c:267
+msgid "show object type"
+msgstr "zeigt Objektart"
 
-#: builtin/checkout.c:193
-#, c-format
-msgid "path '%s': cannot merge"
-msgstr "Pfad '%s': kann nicht zusammenführen"
+#: builtin/cat-file.c:268
+msgid "show object size"
+msgstr "zeigt Objektgröße"
 
-#: builtin/checkout.c:210
-#, c-format
-msgid "Unable to add merge result for '%s'"
-msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen."
+#: builtin/cat-file.c:270
+msgid "exit with zero when there's no error"
+msgstr "beendet mit Rückgabewert 0, wenn kein Fehler aufgetreten ist"
 
-#: builtin/checkout.c:235 builtin/checkout.c:392
-msgid "corrupt index file"
-msgstr "beschädigte Bereitstellungsdatei"
+#: builtin/cat-file.c:271
+msgid "pretty-print object's content"
+msgstr "ansprechende Anzeige des Objektinhaltes"
 
-#: builtin/checkout.c:265 builtin/checkout.c:272
-#, c-format
-msgid "path '%s' is unmerged"
-msgstr "Pfad '%s' ist nicht zusammengeführt."
+#: builtin/cat-file.c:273
+msgid "for blob objects, run textconv on object's content"
+msgstr "führt eine Textkonvertierung auf den Inhalt von Blob-Objekten aus"
 
-#: builtin/checkout.c:303 builtin/checkout.c:498 builtin/clone.c:586
-#: builtin/merge.c:811
-msgid "unable to write new index file"
-msgstr "Konnte neue Bereitstellungsdatei nicht schreiben."
+#: builtin/cat-file.c:275
+msgid "show info and content of objects fed from the standard input"
+msgstr ""
+"Anzeige von Informationen und Inhalt von Objekten, gelesen von der Standard-"
+"Eingabe"
 
-#: builtin/checkout.c:414
-msgid "you need to resolve your current index first"
-msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen."
+#: builtin/cat-file.c:278
+msgid "show info about objects fed from the standard input"
+msgstr ""
+"Anzeige von Informationen über Objekte, gelesen von der Standard-Eingabe"
+
+#: builtin/check-attr.c:11
+msgid "git check-attr [-a | --all | attr...] [--] pathname..."
+msgstr "git check-attr [-a | --all | Attribut...] [--] Pfadname..."
+
+#: builtin/check-attr.c:12
+msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"
+msgstr "git check-attr --stdin [-z] [-a | --all | Attribut...] < <Liste-von-Pfaden>"
+
+#: builtin/check-attr.c:19
+msgid "report all attributes set on file"
+msgstr "gibt alle Attribute einer Datei aus"
+
+#: builtin/check-attr.c:20
+msgid "use .gitattributes only from the index"
+msgstr "verwendet .gitattributes nur von der Bereitstellung"
+
+#: builtin/check-attr.c:21 builtin/hash-object.c:75
+msgid "read file names from stdin"
+msgstr "liest Dateinamen von der Standard-Eingabe"
+
+#: builtin/check-attr.c:23
+msgid "input paths are terminated by a null character"
+msgstr "Eingabepfade sind durch ein NUL Zeichen abgeschlossen"
+
+#: builtin/checkout-index.c:126
+msgid "git checkout-index [options] [--] [<file>...]"
+msgstr "git checkout-index [Optionen] [--] [<Datei>...]"
+
+#: builtin/checkout-index.c:187
+msgid "check out all files in the index"
+msgstr "checkt alle Dateien in der Bereitstellung aus"
+
+#: builtin/checkout-index.c:188
+msgid "force overwrite of existing files"
+msgstr "erzwingt das Überschreiben bereits existierender Dateien"
+
+#: builtin/checkout-index.c:190
+msgid "no warning for existing files and files not in index"
+msgstr ""
+"keine Warnung für existierende Dateien, und Dateien, die sich nicht in der "
+"Bereitstellung befinden"
+
+#: builtin/checkout-index.c:192
+msgid "don't checkout new files"
+msgstr "checkt keine neuen Dateien aus"
+
+#: builtin/checkout-index.c:194
+msgid "update stat information in the index file"
+msgstr "aktualisiert Dateiinformationen in der Bereitstellungsdatei"
+
+#: builtin/checkout-index.c:200
+msgid "read list of paths from the standard input"
+msgstr "liest eine Liste von Pfaden von der Standard-Eingabe"
+
+#: builtin/checkout-index.c:202
+msgid "write the content to temporary files"
+msgstr "schreibt den Inhalt in temporäre Dateien"
+
+#: builtin/checkout-index.c:203 builtin/column.c:30
+msgid "string"
+msgstr "Zeichenkette"
+
+#: builtin/checkout-index.c:204
+msgid "when creating files, prepend <string>"
+msgstr ""
+"wenn Dateien erzeugt werden, stelle <Zeichenkette> dem Dateinamen voran"
+
+#: builtin/checkout-index.c:207
+msgid "copy out the files from named stage"
+msgstr "kopiert Dateien von dem benannten Stand"
+
+#: builtin/checkout.c:25
+msgid "git checkout [options] <branch>"
+msgstr "git checkout [Optionen] <Zweig>"
+
+#: builtin/checkout.c:26
+msgid "git checkout [options] [<branch>] -- <file>..."
+msgstr "git checkout [Optionen] [Zweig>] -- <Datei>..."
+
+#: builtin/checkout.c:116 builtin/checkout.c:149
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr "Pfad '%s' hat nicht unsere Version."
+
+#: builtin/checkout.c:118 builtin/checkout.c:151
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "Pfad '%s' hat nicht deren Version."
 
-#: builtin/checkout.c:533
+#: builtin/checkout.c:134
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr "Pfad '%s' hat nicht alle notwendigen Versionen."
+
+#: builtin/checkout.c:178
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr "Pfad '%s' hat nicht die notwendigen Versionen."
+
+#: builtin/checkout.c:195
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "Pfad '%s': kann nicht zusammenführen"
+
+#: builtin/checkout.c:212
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen."
+
+#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
+#: builtin/checkout.c:245
+#, c-format
+msgid "'%s' cannot be used with updating paths"
+msgstr "'%s' kann nicht mit Pfaden benutzt werden"
+
+#: builtin/checkout.c:248 builtin/checkout.c:251
+#, c-format
+msgid "'%s' cannot be used with %s"
+msgstr "'%s' kann nicht mit '%s' benutzt werden"
+
+#: builtin/checkout.c:254
+#, c-format
+msgid "Cannot update paths and switch to branch '%s' at the same time."
+msgstr "Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln"
+
+#: builtin/checkout.c:265 builtin/checkout.c:426
+msgid "corrupt index file"
+msgstr "beschädigte Bereitstellungsdatei"
+
+#: builtin/checkout.c:295 builtin/checkout.c:302
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr "Pfad '%s' ist nicht zusammengeführt."
+
+#: builtin/checkout.c:448
+msgid "you need to resolve your current index first"
+msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen."
+
+#: builtin/checkout.c:569
 #, c-format
 msgid "Can not do reflog for '%s'\n"
 msgstr "Konnte \"reflog\" für '%s' nicht durchführen\n"
 
-#: builtin/checkout.c:566
+#: builtin/checkout.c:602
 msgid "HEAD is now at"
 msgstr "Zweigspitze (HEAD) ist jetzt bei"
 
-#: builtin/checkout.c:573
+#: builtin/checkout.c:609
 #, c-format
 msgid "Reset branch '%s'\n"
 msgstr "Setze Zweig '%s' zurück\n"
 
-#: builtin/checkout.c:576
+#: builtin/checkout.c:612
 #, c-format
 msgid "Already on '%s'\n"
 msgstr "Bereits auf '%s'\n"
 
-#: builtin/checkout.c:580
+#: builtin/checkout.c:616
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
 msgstr "Gewechselt zu zurückgesetztem Zweig '%s'\n"
 
-#: builtin/checkout.c:582
+#: builtin/checkout.c:618 builtin/checkout.c:955
 #, c-format
 msgid "Switched to a new branch '%s'\n"
 msgstr "Gewechselt zu einem neuen Zweig '%s'\n"
 
-#: builtin/checkout.c:584
+#: builtin/checkout.c:620
 #, c-format
 msgid "Switched to branch '%s'\n"
 msgstr "Gewechselt zu Zweig '%s'\n"
 
-#: builtin/checkout.c:640
+#: builtin/checkout.c:676
 #, c-format
 msgid " ... and %d more.\n"
 msgstr " ... und %d weitere.\n"
 
 #. The singular version
-#: builtin/checkout.c:646
+#: builtin/checkout.c:682
 #, c-format
 msgid ""
 "Warning: you are leaving %d commit behind, not connected to\n"
@@ -2241,7 +2808,7 @@ msgstr[1] ""
 "\n"
 "%s\n"
 
-#: builtin/checkout.c:664
+#: builtin/checkout.c:700
 #, c-format
 msgid ""
 "If you want to keep them by creating a new branch, this may be a good time\n"
@@ -2256,92 +2823,151 @@ msgstr ""
 " git branch neuer_zweig_name %s\n"
 "\n"
 
-#: builtin/checkout.c:694
+#: builtin/checkout.c:730
 msgid "internal error in revision walk"
 msgstr "interner Fehler im Revisionsgang"
 
-#: builtin/checkout.c:698
+#: builtin/checkout.c:734
 msgid "Previous HEAD position was"
 msgstr "Vorherige Position der Zweigspitze (HEAD) war"
 
-#: builtin/checkout.c:724 builtin/checkout.c:919
+#: builtin/checkout.c:761 builtin/checkout.c:950
 msgid "You are on a branch yet to be born"
 msgstr "du bist auf einem Zweig, der noch geboren wird"
 
 #. case (1)
-#: builtin/checkout.c:855
+#: builtin/checkout.c:886
 #, c-format
 msgid "invalid reference: %s"
 msgstr "Ungültige Referenz: %s"
 
 #. case (1): want a tree
-#: builtin/checkout.c:894
+#: builtin/checkout.c:925
 #, c-format
 msgid "reference is not a tree: %s"
 msgstr "Referenz ist kein Baum: %s"
 
-#: builtin/checkout.c:976
-msgid "-B cannot be used with -b"
-msgstr "-B kann nicht mit -b benutzt werden"
+#: builtin/checkout.c:964
+msgid "paths cannot be used with switching branches"
+msgstr "Pfade können nicht mit dem Wechseln von Zweigen benutzt werden"
 
-#: builtin/checkout.c:985
-msgid "--patch is incompatible with all other options"
-msgstr "--patch ist inkompatibel mit allen anderen Optionen"
+#: builtin/checkout.c:967 builtin/checkout.c:971
+#, c-format
+msgid "'%s' cannot be used with switching branches"
+msgstr "'%s' kann nicht mit dem Wechseln von Zweigen benutzt werden"
 
-#: builtin/checkout.c:988
-msgid "--detach cannot be used with -b/-B/--orphan"
-msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden"
+#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
+#: builtin/checkout.c:986
+#, c-format
+msgid "'%s' cannot be used with '%s'"
+msgstr "'%s' kann nicht mit '%s' benutzt werden"
 
-#: builtin/checkout.c:990
-msgid "--detach cannot be used with -t"
-msgstr "--detach kann nicht mit -t benutzt werden"
+#: builtin/checkout.c:991
+#, c-format
+msgid "Cannot switch branch to a non-commit '%s'"
+msgstr "Kann Zweig nicht zu Nicht-Version '%s' wechseln"
 
-#: builtin/checkout.c:996
-msgid "--track needs a branch name"
-msgstr "--track benötigt einen Zweignamen"
+#: builtin/checkout.c:1012 builtin/gc.c:177
+msgid "suppress progress reporting"
+msgstr "unterdrückt Fortschrittsanzeige"
 
-#: builtin/checkout.c:1003
-msgid "Missing branch name; try -b"
-msgstr "Vermisse Zweignamen; versuche -b"
+#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
+#: builtin/remote.c:169 builtin/remote.c:171
+msgid "branch"
+msgstr "Zweig"
+
+#: builtin/checkout.c:1014
+msgid "create and checkout a new branch"
+msgstr "erzeugt und checkt einen neuen Zweig aus"
+
+#: builtin/checkout.c:1016
+msgid "create/reset and checkout a branch"
+msgstr "erzeugt/setzt neu und checkt einen Zweig aus"
+
+#: builtin/checkout.c:1017
+msgid "create reflog for new branch"
+msgstr "erzeugt Referenzprotokoll für den neuen Zweig"
 
-#: builtin/checkout.c:1009
-msgid "--orphan and -b|-B are mutually exclusive"
-msgstr "--orphan und -b|-B sind gegenseitig exklusiv"
+#: builtin/checkout.c:1018
+msgid "detach the HEAD at named commit"
+msgstr "setzt die Zweigspitze (HEAD) zu benannter Version"
 
-#: builtin/checkout.c:1011
-msgid "--orphan cannot be used with -t"
-msgstr "--orphan kann nicht mit -t benutzt werden"
+#: builtin/checkout.c:1019
+msgid "set upstream info for new branch"
+msgstr "setzt Informationen zum externen Übernahmezweig für den neuen Zweig"
 
 #: builtin/checkout.c:1021
-msgid "git checkout: -f and -m are incompatible"
-msgstr "git checkout: -f und -m sind inkompatibel"
+msgid "new branch"
+msgstr "neuer Zweig"
+
+#: builtin/checkout.c:1021
+msgid "new unparented branch"
+msgstr "neuer Zweig ohne Elternversion"
+
+#: builtin/checkout.c:1022
+msgid "checkout our version for unmerged files"
+msgstr "checkt unsere Variante für nicht zusammengeführte Dateien aus"
 
-#: builtin/checkout.c:1055
+#: builtin/checkout.c:1024
+msgid "checkout their version for unmerged files"
+msgstr "checkt ihre Variante für nicht zusammengeführte Dateien aus"
+
+#: builtin/checkout.c:1026
+msgid "force checkout (throw away local modifications)"
+msgstr "erzwingt Auschecken (verwirft lokale Änderungen)"
+
+#: builtin/checkout.c:1027
+msgid "perform a 3-way merge with the new branch"
+msgstr "führt eine 3-Wege-Zusammenführung mit dem neuen Zweig aus"
+
+#: builtin/checkout.c:1028 builtin/merge.c:215
+msgid "update ignored files (default)"
+msgstr "aktualisiert ignorierte Dateien (Standard)"
+
+#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241
+msgid "style"
+msgstr "Stil"
+
+#: builtin/checkout.c:1030
+msgid "conflict style (merge or diff3)"
+msgstr "Konfliktstil (merge oder diff3)"
+
+#: builtin/checkout.c:1033
+msgid "second guess 'git checkout no-such-branch'"
+msgstr "second guess 'git checkout no-such-branch'"
+
+#: builtin/checkout.c:1057
+msgid "-b, -B and --orphan are mutually exclusive"
+msgstr "-b, -B und --orphan schliessen sich gegenseitig aus"
+
+#: builtin/checkout.c:1074
+msgid "--track needs a branch name"
+msgstr "--track benötigt einen Zweignamen"
+
+#: builtin/checkout.c:1081
+msgid "Missing branch name; try -b"
+msgstr "Vermisse Zweignamen; versuche -b"
+
+#: builtin/checkout.c:1116
 msgid "invalid path specification"
 msgstr "ungültige Pfadspezifikation"
 
-#: builtin/checkout.c:1063
+#: builtin/checkout.c:1123
 #, c-format
 msgid ""
-"git checkout: updating paths is incompatible with switching branches.\n"
+"Cannot update paths and switch to branch '%s' at the same time.\n"
 "Did you intend to checkout '%s' which can not be resolved as commit?"
 msgstr ""
-"git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel "
-"von Zweigen.\n"
+"Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln.\n"
 "Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst "
 "werden kann?"
 
-#: builtin/checkout.c:1065
-msgid "git checkout: updating paths is incompatible with switching branches."
-msgstr ""
-"git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel "
-"von Zweigen."
-
-#: builtin/checkout.c:1070
-msgid "git checkout: --detach does not take a path argument"
-msgstr "git checkout: --detach nimmt kein Pfad-Argument"
+#: builtin/checkout.c:1128
+#, c-format
+msgid "git checkout: --detach does not take a path argument '%s'"
+msgstr "git checkout: --detach nimmt kein Pfad-Argument '%s'"
 
-#: builtin/checkout.c:1073
+#: builtin/checkout.c:1132
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
@@ -2349,13 +2975,38 @@ msgstr ""
 "git checkout: --ours/--theirs, --force und --merge sind inkompatibel wenn\n"
 "du aus der Bereitstellung auscheckst."
 
-#: builtin/checkout.c:1092
-msgid "Cannot switch branch to a non-commit."
-msgstr "Kann Zweig nur zu einer Version wechseln."
+#: builtin/clean.c:19
+msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr "git clean [-d] [-f] [-n] [-q] [-e <Muster>] [-x | -X] [--] <Pfade>..."
+
+#: builtin/clean.c:51
+msgid "do not print names of files removed"
+msgstr "gibt keine Namen von gelöschten Dateien aus"
+
+#: builtin/clean.c:53
+msgid "force"
+msgstr "erzwingt Aktion"
+
+#: builtin/clean.c:55
+msgid "remove whole directories"
+msgstr "löscht ganze Verzeichnisse"
+
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182
+msgid "pattern"
+msgstr "Muster"
+
+#: builtin/clean.c:57
+msgid "add <pattern> to ignore rules"
+msgstr "fügt <Muster> zu den Regeln für ignorierte Pfade hinzu"
+
+#: builtin/clean.c:58
+msgid "remove ignored files, too"
+msgstr "löscht auch ignorierte Dateien"
 
-#: builtin/checkout.c:1095
-msgid "--ours/--theirs is incompatible with switching branches."
-msgstr "--ours/--theirs ist inkompatibel mit den Wechseln von Zweigen."
+#: builtin/clean.c:60
+msgid "remove only ignored files"
+msgstr "löscht nur ignorierte Dateien"
 
 #: builtin/clean.c:78
 msgid "-x and -X cannot be used together"
@@ -2379,28 +3030,122 @@ msgstr ""
 #: builtin/clean.c:155 builtin/clean.c:176
 #, c-format
 msgid "Would remove %s\n"
-msgstr "Würde %s entfernen\n"
+msgstr "Würde %s löschen\n"
 
 #: builtin/clean.c:159 builtin/clean.c:179
 #, c-format
 msgid "Removing %s\n"
-msgstr "Entferne %s\n"
+msgstr "Lösche %s\n"
 
 #: builtin/clean.c:162 builtin/clean.c:182
 #, c-format
 msgid "failed to remove %s"
-msgstr "Fehler beim Entfernen von %s"
+msgstr "Fehler beim Löschen von %s"
 
 #: builtin/clean.c:166
 #, c-format
 msgid "Would not remove %s\n"
-msgstr "Würde nicht entfernen %s\n"
+msgstr "Würde '%s' nicht löschen\n"
 
 #: builtin/clean.c:168
 #, c-format
 msgid "Not removing %s\n"
 msgstr "Entferne nicht %s\n"
 
+#: builtin/clone.c:36
+msgid "git clone [options] [--] <repo> [<dir>]"
+msgstr "git clone [Optionen] [--] <Projektarchiv> [<Verzeichnis>]"
+
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212
+#: builtin/push.c:399
+msgid "force progress reporting"
+msgstr "erzwingt Fortschrittsanzeige"
+
+#: builtin/clone.c:66
+msgid "don't create a checkout"
+msgstr "kein Auschecken"
+
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
+msgid "create a bare repository"
+msgstr "erstellt ein bloßes Projektarchiv"
+
+#: builtin/clone.c:72
+msgid "create a mirror repository (implies bare)"
+msgstr "erstellt ein Spiegelarchiv (impliziert bloßes Projektarchiv)"
+
+#: builtin/clone.c:74
+msgid "to clone from a local repository"
+msgstr "um von einem lokalen Projektarchiv zu klonen"
+
+#: builtin/clone.c:76
+msgid "don't use local hardlinks, always copy"
+msgstr "benutzt lokal keine harten Links, immer Kopien"
+
+#: builtin/clone.c:78
+msgid "setup as shared repository"
+msgstr "Einrichtung als verteiltes Projektarchiv"
+
+#: builtin/clone.c:80 builtin/clone.c:82
+msgid "initialize submodules in the clone"
+msgstr "initialisiert Unterprojekte im Klon"
+
+#: builtin/clone.c:83 builtin/init-db.c:485
+msgid "template-directory"
+msgstr "Vorlagenverzeichnis"
+
+#: builtin/clone.c:84 builtin/init-db.c:486
+msgid "directory from which templates will be used"
+msgstr "Verzeichnis, von welchem die Vorlagen verwendet werden"
+
+#: builtin/clone.c:86
+msgid "reference repository"
+msgstr "referenziert Projektarchiv"
+
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
+msgid "name"
+msgstr "Name"
+
+#: builtin/clone.c:88
+msgid "use <name> instead of 'origin' to track upstream"
+msgstr "benutzt <Name> statt 'origin' für externes Projektarchiv"
+
+#: builtin/clone.c:90
+msgid "checkout <branch> instead of the remote's HEAD"
+msgstr ""
+"checkt <Zweig> aus, anstatt Zweigspitze (HEAD) des externen Projektarchivs"
+
+#: builtin/clone.c:92
+msgid "path to git-upload-pack on the remote"
+msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite"
+
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
+msgid "depth"
+msgstr "Tiefe"
+
+#: builtin/clone.c:94
+msgid "create a shallow clone of that depth"
+msgstr "erstellt einen flachen Klon mit dieser Tiefe"
+
+#: builtin/clone.c:96
+msgid "clone only one branch, HEAD or --branch"
+msgstr "klont nur einen Zweig, Zweigspitze (HEAD) oder --branch"
+
+#: builtin/clone.c:97 builtin/init-db.c:494
+msgid "gitdir"
+msgstr ".git-Verzeichnis"
+
+#: builtin/clone.c:98 builtin/init-db.c:495
+msgid "separate git dir from working tree"
+msgstr "separiert Git-Verzeichnis vom Arbeitsbaum"
+
+#: builtin/clone.c:99
+msgid "key=value"
+msgstr "Schlüssel=Wert"
+
+#: builtin/clone.c:100
+msgid "set config inside the new repository"
+msgstr "setzt Konfiguration innerhalb des neuen Projektarchivs"
+
 #: builtin/clone.c:243
 #, c-format
 msgid "reference repository '%s' is not a local directory."
@@ -2452,77 +3197,113 @@ msgstr ""
 "Externe Zweigspitze (HEAD) bezieht sich auf eine nicht existierende Referenz "
 "und kann nicht ausgecheckt werden.\n"
 
-#: builtin/clone.c:642
+#: builtin/clone.c:690
 msgid "Too many arguments."
 msgstr "Zu viele Argumente."
 
-#: builtin/clone.c:646
+#: builtin/clone.c:694
 msgid "You must specify a repository to clone."
 msgstr "Du musst ein Projektarchiv zum Klonen angeben."
 
-#: builtin/clone.c:657
+#: builtin/clone.c:705
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "--bare und --origin %s Optionen sind inkompatibel."
 
-#: builtin/clone.c:671
+#: builtin/clone.c:719
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "Projektarchiv '%s' existiert nicht."
 
-#: builtin/clone.c:676
+#: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://."
 
-#: builtin/clone.c:686
+#: builtin/clone.c:734
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
 msgstr "Zielpfad '%s' existiert bereits und ist kein leeres Verzeichnis."
 
-#: builtin/clone.c:696
+#: builtin/clone.c:744
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "Arbeitsbaum '%s' existiert bereits."
 
-#: builtin/clone.c:709 builtin/clone.c:723
+#: builtin/clone.c:757 builtin/clone.c:771
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
 
-#: builtin/clone.c:712
+#: builtin/clone.c:760
 #, c-format
 msgid "could not create work tree dir '%s'."
 msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen."
 
-#: builtin/clone.c:731
+#: builtin/clone.c:779
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "Klone in bloßes Projektarchiv '%s'...\n"
 
-#: builtin/clone.c:733
+#: builtin/clone.c:781
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "Klone nach '%s'...\n"
 
-#: builtin/clone.c:789
+#: builtin/clone.c:823
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Weiß nicht wie %s zu klonen ist."
 
-#: builtin/clone.c:838
+#: builtin/clone.c:872
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden"
 
-#: builtin/clone.c:845
+#: builtin/clone.c:879
 msgid "You appear to have cloned an empty repository."
 msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben."
 
+#: builtin/column.c:9
+msgid "git column [options]"
+msgstr "git column [Optionen]"
+
+#: builtin/column.c:26
+msgid "lookup config vars"
+msgstr "schlägt Konfigurationsvariablen nach"
+
+#: builtin/column.c:27 builtin/column.c:28
+msgid "layout to use"
+msgstr "zu verwendende Anordnung"
+
+#: builtin/column.c:29
+msgid "Maximum width"
+msgstr "maximale Breite"
+
+#: builtin/column.c:30
+msgid "Padding space on left border"
+msgstr "Abstand zum linken Rand"
+
+#: builtin/column.c:31
+msgid "Padding space on right border"
+msgstr "Abstand zur rechten Rand"
+
+#: builtin/column.c:32
+msgid "Padding space between columns"
+msgstr "Abstand zwischen Spalten"
+
 #: builtin/column.c:51
 msgid "--command must be the first argument"
 msgstr "Option --command muss zuerst angegeben werden"
 
-#: builtin/commit.c:43
+#: builtin/commit.c:34
+msgid "git commit [options] [--] <filepattern>..."
+msgstr "git commit [Optionen] [--] <Dateimuster>..."
+
+#: builtin/commit.c:39
+msgid "git status [options] [--] <filepattern>..."
+msgstr "git status [Optionen] [--] <Dateimuster>..."
+
+#: builtin/commit.c:44
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
@@ -2548,7 +3329,7 @@ msgstr ""
 "\n"
 "    git commit --amend --reset-author\n"
 
-#: builtin/commit.c:55
+#: builtin/commit.c:56
 msgid ""
 "You asked to amend the most recent commit, but doing so would make\n"
 "it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -2558,7 +3339,7 @@ msgstr ""
 "machen. Du kannst Dein Kommando mit --allow-empty wiederholen, oder die\n"
 "Version mit \"git reset HEAD^\" vollständig entfernen.\n"
 
-#: builtin/commit.c:60
+#: builtin/commit.c:61
 msgid ""
 "The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
 "If you wish to commit it anyway, use:\n"
@@ -2575,97 +3356,97 @@ msgstr ""
 "\n"
 "Andernfalls benutze bitte 'git reset'\n"
 
-#: builtin/commit.c:256
+#: builtin/commit.c:258
 msgid "failed to unpack HEAD tree object"
 msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)."
 
-#: builtin/commit.c:298
+#: builtin/commit.c:300
 msgid "unable to create temporary index"
 msgstr "Konnte temporäre Bereitstellung nicht erstellen."
 
-#: builtin/commit.c:304
+#: builtin/commit.c:306
 msgid "interactive add failed"
 msgstr "interaktives Hinzufügen fehlgeschlagen"
 
-#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
+#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
 msgid "unable to write new_index file"
 msgstr "Konnte new_index Datei nicht schreiben"
 
-#: builtin/commit.c:389
+#: builtin/commit.c:391
 msgid "cannot do a partial commit during a merge."
 msgstr ""
 "Kann keine partielle Eintragung durchführen, während eine Zusammenführung im "
 "Gange ist."
 
-#: builtin/commit.c:391
+#: builtin/commit.c:393
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr ""
 "Kann keine partielle Eintragung durchführen, während \"cherry-pick\" im "
 "Gange ist."
 
-#: builtin/commit.c:401
+#: builtin/commit.c:403
 msgid "cannot read the index"
 msgstr "Kann Bereitstellung nicht lesen"
 
-#: builtin/commit.c:421
+#: builtin/commit.c:423
 msgid "unable to write temporary index file"
 msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben."
 
-#: builtin/commit.c:496 builtin/commit.c:502
+#: builtin/commit.c:511 builtin/commit.c:517
 #, c-format
 msgid "invalid commit: %s"
 msgstr "Ungültige Version: %s"
 
-#: builtin/commit.c:525
+#: builtin/commit.c:540
 msgid "malformed --author parameter"
 msgstr "Fehlerhafter --author Parameter"
 
-#: builtin/commit.c:585
+#: builtin/commit.c:560
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "Fehlerhafte Identifikations-String: '%s'"
 
-#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970
+#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "Konnte Version %s nicht nachschlagen"
 
-#: builtin/commit.c:635 builtin/shortlog.c:296
+#: builtin/commit.c:610 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(lese Log-Nachricht von Standard-Eingabe)\n"
 
-#: builtin/commit.c:637
+#: builtin/commit.c:612
 msgid "could not read log from standard input"
 msgstr "Konnte Log nicht von Standard-Eingabe lesen."
 
-#: builtin/commit.c:641
+#: builtin/commit.c:616
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "Konnte Log-Datei '%s' nicht lesen"
 
-#: builtin/commit.c:647
+#: builtin/commit.c:622
 msgid "commit has empty message"
 msgstr "Version hat eine leere Beschreibung"
 
-#: builtin/commit.c:663
+#: builtin/commit.c:638
 msgid "could not read MERGE_MSG"
 msgstr "Konnte MERGE_MSG nicht lesen"
 
-#: builtin/commit.c:667
+#: builtin/commit.c:642
 msgid "could not read SQUASH_MSG"
 msgstr "Konnte SQUASH_MSG nicht lesen"
 
-#: builtin/commit.c:671
+#: builtin/commit.c:646
 #, c-format
 msgid "could not read '%s'"
 msgstr "Konnte '%s' nicht lesen"
 
-#: builtin/commit.c:723
+#: builtin/commit.c:707
 msgid "could not write commit template"
 msgstr "Konnte Versionsvorlage nicht schreiben"
 
-#: builtin/commit.c:734
+#: builtin/commit.c:718
 #, c-format
 msgid ""
 "\n"
@@ -2676,11 +3457,11 @@ msgid ""
 msgstr ""
 "\n"
 "Es sieht so aus, als trägst du eine Zusammenführung ein.\n"
-"Falls das nicht korrekt ist, entferne bitte die Datei\n"
+"Falls das nicht korrekt ist, lösche bitte die Datei\n"
 "\t%s\n"
 "und versuche es erneut.\n"
 
-#: builtin/commit.c:739
+#: builtin/commit.c:723
 #, c-format
 msgid ""
 "\n"
@@ -2691,11 +3472,11 @@ msgid ""
 msgstr ""
 "\n"
 "Es sieht so aus, als trägst du ein \"cherry-pick\" ein.\n"
-"Falls das nicht korrekt ist, entferne bitte die Datei\n"
+"Falls das nicht korrekt ist, lösche bitte die Datei\n"
 "\t%s\n"
 "und versuche es erneut.\n"
 
-#: builtin/commit.c:751
+#: builtin/commit.c:735
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -2704,7 +3485,7 @@ msgstr ""
 "die mit '#' beginnen, werden ignoriert, und eine leere Versionsbeschreibung\n"
 "bricht die Eintragung ab.\n"
 
-#: builtin/commit.c:756
+#: builtin/commit.c:740
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -2715,118 +3496,320 @@ msgstr ""
 "entfernen.\n"
 "Eine leere Versionsbeschreibung bricht die Eintragung ab.\n"
 
-#: builtin/commit.c:769
+#: builtin/commit.c:753
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sAutor:    %s"
 
-#: builtin/commit.c:776
+#: builtin/commit.c:760
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sEintragender: %s"
 
-#: builtin/commit.c:796
+#: builtin/commit.c:780
 msgid "Cannot read index"
 msgstr "Kann Bereitstellung nicht lesen"
 
-#: builtin/commit.c:833
+#: builtin/commit.c:817
 msgid "Error building trees"
 msgstr "Fehler beim Erzeugen der Zweige"
 
-#: builtin/commit.c:848 builtin/tag.c:361
+#: builtin/commit.c:832 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "Bitte liefere eine Beschreibung entweder mit der Option -m oder -F.\n"
 
-#: builtin/commit.c:945
+#: builtin/commit.c:929
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "Kein existierender Autor mit '%s' gefunden."
 
-#: builtin/commit.c:960 builtin/commit.c:1160
+#: builtin/commit.c:944 builtin/commit.c:1148
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien"
 
-#: builtin/commit.c:1000
+#: builtin/commit.c:984
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "Verwendung von --reset-author und --author macht keinen Sinn."
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:995
 msgid "You have nothing to amend."
 msgstr "Du hast nichts zum nachbessern."
 
-#: builtin/commit.c:1014
+#: builtin/commit.c:998
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr "Eine Zusammenführung ist im Gange -- kann nicht nachbessern."
 
-#: builtin/commit.c:1016
+#: builtin/commit.c:1000
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr "\"cherry-pick\" ist im Gange -- kann nicht nachbessern."
 
-#: builtin/commit.c:1019
+#: builtin/commit.c:1003
 msgid "Options --squash and --fixup cannot be used together"
 msgstr ""
 "Die Optionen --squash und --fixup können nicht gemeinsam benutzt werden."
 
-#: builtin/commit.c:1029
+#: builtin/commit.c:1013
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "Nur eines von -c/-C/-F/--fixup kann benutzt werden."
 
-#: builtin/commit.c:1031
+#: builtin/commit.c:1015
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr "Option -m kann nicht mit -c/-C/-F/--fixup kombiniert werden"
 
-#: builtin/commit.c:1039
+#: builtin/commit.c:1023
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr "--reset--author kann nur mit -C, -c oder --amend benutzt werden"
 
-#: builtin/commit.c:1056
+#: builtin/commit.c:1040
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 "Nur eines von --include/--only/--all/--interactive/--patch kann benutzt "
 "werden."
 
-#: builtin/commit.c:1058
+#: builtin/commit.c:1042
 msgid "No paths with --include/--only does not make sense."
 msgstr "--include/--only machen ohne Pfade keinen Sinn."
 
-#: builtin/commit.c:1060
+#: builtin/commit.c:1044
 msgid "Clever... amending the last one with dirty index."
 msgstr ""
 "Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern."
 
-#: builtin/commit.c:1062
+#: builtin/commit.c:1046
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr ""
 "Explizite Pfade ohne -i oder -o angegeben; unter der Annahme von --only "
 "Pfaden..."
 
-#: builtin/commit.c:1072 builtin/tag.c:577
+#: builtin/commit.c:1056 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Ungültiger \"cleanup\" Modus %s"
 
-#: builtin/commit.c:1077
+#: builtin/commit.c:1061
 msgid "Paths with -a does not make sense."
 msgstr "Pfade mit -a machen keinen Sinn."
 
-#: builtin/commit.c:1260
+#: builtin/commit.c:1067 builtin/commit.c:1202
+msgid "--long and -z are incompatible"
+msgstr "--long und -z sind inkompatibel"
+
+#: builtin/commit.c:1162 builtin/commit.c:1398
+msgid "show status concisely"
+msgstr "zeigt Status im Kurzformat"
+
+#: builtin/commit.c:1164 builtin/commit.c:1400
+msgid "show branch information"
+msgstr "zeigt Zweiginformationen"
+
+#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389
+msgid "machine-readable output"
+msgstr "maschinenlesbare Ausgabe"
+
+#: builtin/commit.c:1169 builtin/commit.c:1404
+msgid "show status in long format (default)"
+msgstr "zeigt Status im Langformat (Standard)"
+
+#: builtin/commit.c:1172 builtin/commit.c:1407
+msgid "terminate entries with NUL"
+msgstr "schließt Einträge mit NUL-Zeichen ab"
+
+#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636
+#: builtin/fast-export.c:639 builtin/tag.c:461
+msgid "mode"
+msgstr "Modus"
+
+#: builtin/commit.c:1175 builtin/commit.c:1410
+msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
+msgstr ""
+"zeigt nicht beobachtete Dateien, optionale Modi: all, normal, no. (Standard: "
+"all)"
+
+#: builtin/commit.c:1178
+msgid "show ignored files"
+msgstr "zeigt ignorierte Dateien"
+
+#: builtin/commit.c:1179 parse-options.h:151
+msgid "when"
+msgstr "wann"
+
+#: builtin/commit.c:1180
+msgid ""
+"ignore changes to submodules, optional when: all, dirty, untracked. "
+"(Default: all)"
+msgstr ""
+"ignoriert Änderungen in Unterprojekten, optional wenn: all, dirty, "
+"untracked. (Standard: all)"
+
+#: builtin/commit.c:1182
+msgid "list untracked files in columns"
+msgstr "listet unbeobachtete Dateien in Spalten auf"
+
+#: builtin/commit.c:1256
 msgid "couldn't look up newly created commit"
 msgstr "Konnte neu erstellte Version nicht nachschlagen."
 
-#: builtin/commit.c:1262
+#: builtin/commit.c:1258
 msgid "could not parse newly created commit"
 msgstr "Konnte neulich erstellte Version nicht analysieren."
 
-#: builtin/commit.c:1303
+#: builtin/commit.c:1299
 msgid "detached HEAD"
 msgstr "losgelöste Zweigspitze (HEAD)"
 
-#: builtin/commit.c:1305
+#: builtin/commit.c:1301
 msgid " (root-commit)"
 msgstr " (Basis-Version)"
 
+#: builtin/commit.c:1368
+msgid "suppress summary after successful commit"
+msgstr "unterdrückt Zusammenfassung nach erfolgreicher Eintragung"
+
+#: builtin/commit.c:1369
+msgid "show diff in commit message template"
+msgstr "zeigt Unterschiede in Versionsbeschreibungsvorlage an"
+
+#: builtin/commit.c:1371
+msgid "Commit message options"
+msgstr "Optionen für Versionsbeschreibung"
+
+#: builtin/commit.c:1372 builtin/tag.c:459
+msgid "read message from file"
+msgstr "liest Beschreibung von Datei"
+
+#: builtin/commit.c:1373
+msgid "author"
+msgstr "Autor"
+
+#: builtin/commit.c:1373
+msgid "override author for commit"
+msgstr "überschreibt Autor von Version"
+
+#: builtin/commit.c:1374 builtin/gc.c:178
+msgid "date"
+msgstr "Datum"
+
+#: builtin/commit.c:1374
+msgid "override date for commit"
+msgstr "überschreibt Datum von Version"
+
+#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/tag.c:457
+msgid "message"
+msgstr "Beschreibung"
+
+#: builtin/commit.c:1375
+msgid "commit message"
+msgstr "Versionsbeschreibung"
+
+#: builtin/commit.c:1376
+msgid "reuse and edit message from specified commit"
+msgstr "verwendet wieder und editiert Beschreibung von der angegebenen Version"
+
+#: builtin/commit.c:1377
+msgid "reuse message from specified commit"
+msgstr "verwendet Beschreibung der angegebenen Version wieder"
+
+#: builtin/commit.c:1378
+msgid "use autosquash formatted message to fixup specified commit"
+msgstr ""
+"benutzt eine automatisch zusammengesetzte Beschreibung zum Nachbessern der "
+"angegebenen Version"
+
+#: builtin/commit.c:1379
+msgid "use autosquash formatted message to squash specified commit"
+msgstr ""
+"benutzt eine automatisch zusammengesetzte Beschreibung zum Zusammenführen "
+"der angegebenen Version"
+
+#: builtin/commit.c:1380
+msgid "the commit is authored by me now (used with -C/-c/--amend)"
+msgstr "Setze mich als Autor der Version (benutzt mit -C/-c/--amend)"
+
+#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109
+msgid "add Signed-off-by:"
+msgstr "fügt 'Signed-off-by:'-Zeile hinzu"
+
+#: builtin/commit.c:1382
+msgid "use specified template file"
+msgstr "benutzt angegebene Vorlagendatei"
+
+#: builtin/commit.c:1383
+msgid "force edit of commit"
+msgstr "erzwingt Bearbeitung der Version"
+
+#: builtin/commit.c:1384
+msgid "default"
+msgstr "Standard"
+
+#: builtin/commit.c:1384 builtin/tag.c:462
+msgid "how to strip spaces and #comments from message"
+msgstr ""
+"wie Leerzeichen und #Kommentare von der Beschreibung getrennt werden sollen"
+
+#: builtin/commit.c:1385
+msgid "include status in commit message template"
+msgstr "fügt Status in die Versionsbeschreibungsvorlage ein"
+
+#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463
+msgid "key id"
+msgstr "Schlüssel-ID"
+
+#: builtin/commit.c:1387 builtin/merge.c:214
+msgid "GPG sign commit"
+msgstr "signiert Version mit GPG"
+
+#. end commit message options
+#: builtin/commit.c:1390
+msgid "Commit contents options"
+msgstr "Optionen für Versionsinhalt"
+
+#: builtin/commit.c:1391
+msgid "commit all changed files"
+msgstr "trägt alle geänderten Dateien ein"
+
+#: builtin/commit.c:1392
+msgid "add specified files to index for commit"
+msgstr "trägt die angegebenen Dateien zusätzlich zur Bereitstellung ein"
+
+#: builtin/commit.c:1393
+msgid "interactively add files"
+msgstr "interaktives Hinzufügen von Dateien"
+
+#: builtin/commit.c:1394
+msgid "interactively add changes"
+msgstr "interaktives Hinzufügen von Änderungen"
+
+#: builtin/commit.c:1395
+msgid "commit only specified files"
+msgstr "trägt nur die angegebenen Dateien ein"
+
+#: builtin/commit.c:1396
+msgid "bypass pre-commit hook"
+msgstr "umgeht \"pre-commit hook\""
+
+#: builtin/commit.c:1397
+msgid "show what would be committed"
+msgstr "zeigt an, was eingetragen werden würde"
+
+#: builtin/commit.c:1408
+msgid "amend previous commit"
+msgstr "ändert vorherige Version"
+
+#: builtin/commit.c:1409
+msgid "bypass post-rewrite hook"
+msgstr "umgeht \"post-rewrite hook\""
+
+#: builtin/commit.c:1414
+msgid "ok to record an empty change"
+msgstr "erlaubt Aufzeichnung einer leeren Änderung"
+
+#: builtin/commit.c:1417
+msgid "ok to record a change with an empty message"
+msgstr "erlaubt Aufzeichnung einer Änderung mit einer leeren Beschreibung"
+
 #: builtin/commit.c:1449
 msgid "could not parse HEAD commit"
 msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren."
@@ -2860,7 +3843,7 @@ msgstr "Eintragung abgebrochen; du hast die Beschreibung nicht editiert.\n"
 msgid "Aborting commit due to empty commit message.\n"
 msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n"
 
-#: builtin/commit.c:1554 builtin/merge.c:935 builtin/merge.c:960
+#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857
 msgid "failed to write commit object"
 msgstr "Fehler beim Schreiben des Versionsobjektes."
 
@@ -2883,6 +3866,134 @@ msgstr ""
 "voll und Dein Kontingent nicht aufgebraucht ist und führe\n"
 "anschließend \"git reset HEAD\" zu Wiederherstellung aus."
 
+#: builtin/config.c:7
+msgid "git config [options]"
+msgstr "git config [Optionen]"
+
+#: builtin/config.c:51
+msgid "Config file location"
+msgstr "Ort der Konfigurationsdatei"
+
+#: builtin/config.c:52
+msgid "use global config file"
+msgstr "benutzt globale Konfigurationsdatei"
+
+#: builtin/config.c:53
+msgid "use system config file"
+msgstr "benutzt systemweite Konfigurationsdatei"
+
+#: builtin/config.c:54
+msgid "use repository config file"
+msgstr "benutzt Konfigurationsdatei des Projektarchivs"
+
+#: builtin/config.c:55
+msgid "use given config file"
+msgstr "benutzt die angegebene Konfigurationsdatei"
+
+#: builtin/config.c:56
+msgid "Action"
+msgstr "Aktion"
+
+#: builtin/config.c:57
+msgid "get value: name [value-regex]"
+msgstr "gibt Wert zurück: Name [Wert-regex]"
+
+#: builtin/config.c:58
+msgid "get all values: key [value-regex]"
+msgstr "gibt alle Werte zurück: Schlüssel [Wert-regex]"
+
+#: builtin/config.c:59
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr "gibt Werte für den regulären Ausdruck zurück: Name-regex [Wert-regex]"
+
+#: builtin/config.c:60
+msgid "replace all matching variables: name value [value_regex]"
+msgstr "ersetzt alle passenden Variablen: Name Wert [Wert-regex] "
+
+#: builtin/config.c:61
+msgid "add a new variable: name value"
+msgstr "fügt neue Variable hinzu: Name Wert"
+
+#: builtin/config.c:62
+msgid "remove a variable: name [value-regex]"
+msgstr "entfernt eine Variable: Name [Wert-regex]"
+
+#: builtin/config.c:63
+msgid "remove all matches: name [value-regex]"
+msgstr "entfernt alle Übereinstimmungen: Name [Wert-regex]"
+
+#: builtin/config.c:64
+msgid "rename section: old-name new-name"
+msgstr "benennt eine Sektion um: alter-Name neuer-Name"
+
+#: builtin/config.c:65
+msgid "remove a section: name"
+msgstr "entfernt eine Sektion: Name"
+
+#: builtin/config.c:66
+msgid "list all"
+msgstr "listet alles auf"
+
+#: builtin/config.c:67
+msgid "open an editor"
+msgstr "öffnet einen Editor"
+
+#: builtin/config.c:68 builtin/config.c:69
+msgid "slot"
+msgstr "Slot"
+
+#: builtin/config.c:68
+msgid "find the color configured: [default]"
+msgstr "findet die konfigurierte Farbe: [Standard]"
+
+#: builtin/config.c:69
+msgid "find the color setting: [stdout-is-tty]"
+msgstr "findet die Farbeinstellung: [Standard-Ausgabe-ist-Terminal]"
+
+#: builtin/config.c:70
+msgid "Type"
+msgstr "Typ"
+
+#: builtin/config.c:71
+msgid "value is \"true\" or \"false\""
+msgstr "Wert ist \"true\" oder \"false\""
+
+#: builtin/config.c:72
+msgid "value is decimal number"
+msgstr "Wert ist eine Dezimalzahl"
+
+#: builtin/config.c:73
+msgid "value is --bool or --int"
+msgstr "Wert ist --bool oder --int"
+
+#: builtin/config.c:74
+msgid "value is a path (file or directory name)"
+msgstr "Wert ist ein Pfad (Datei oder Verzeichnisname)"
+
+#: builtin/config.c:75
+msgid "Other"
+msgstr "Sonstiges"
+
+#: builtin/config.c:76
+msgid "terminate values with NUL byte"
+msgstr "schließt Werte mit NUL-Byte ab"
+
+#: builtin/config.c:77
+msgid "respect include directives on lookup"
+msgstr "beachtet \"include\"-Direktiven beim Nachschlagen"
+
+#: builtin/count-objects.c:69
+msgid "git count-objects [-v]"
+msgstr "git count-objects [-v]"
+
+#: builtin/describe.c:15
+msgid "git describe [options] <committish>*"
+msgstr "git describe [Optionen] <committish>*"
+
+#: builtin/describe.c:16
+msgid "git describe [options] --dirty"
+msgstr "git describe [Optionen] --dirty"
+
 #: builtin/describe.c:234
 #, c-format
 msgid "annotated tag %s not available"
@@ -2955,6 +4066,51 @@ msgstr ""
 "mehr als %i Markierungen gefunden; Führe die ersten %i auf\n"
 "Suche bei %s aufgegeben\n"
 
+#: builtin/describe.c:403
+msgid "find the tag that comes after the commit"
+msgstr "findet die Markierung, die nach der Version kommt"
+
+#: builtin/describe.c:404
+msgid "debug search strategy on stderr"
+msgstr "protokolliert die Suchstrategie in der Standard-Fehlerausgabe"
+
+#: builtin/describe.c:405
+msgid "use any ref in .git/refs"
+msgstr "benutzt jede Referenz in .git/refs"
+
+#: builtin/describe.c:406
+msgid "use any tag in .git/refs/tags"
+msgstr "benutzt alle Markierungen in .git/refs/tags"
+
+#: builtin/describe.c:407
+msgid "always use long format"
+msgstr "benutzt immer langes Format"
+
+#: builtin/describe.c:410
+msgid "only output exact matches"
+msgstr "gibt nur exakte Übereinstimmungen aus"
+
+#: builtin/describe.c:412
+msgid "consider <n> most recent tags (default: 10)"
+msgstr "betrachtet die jüngsten <n> Markierungen (Standard: 10)"
+
+#: builtin/describe.c:414
+msgid "only consider tags matching <pattern>"
+msgstr "betrachtet nur Markierungen die <Muster> entsprechen"
+
+#: builtin/describe.c:416 builtin/name-rev.c:238
+msgid "show abbreviated commit object as fallback"
+msgstr "zeigt gekürztes Versionsobjekt, wenn sonst nichts zutrifft"
+
+#: builtin/describe.c:417
+msgid "mark"
+msgstr "Kennzeichen"
+
+#: builtin/describe.c:418
+msgid "append <mark> on dirty working tree (default: \"-dirty\")"
+msgstr ""
+"fügt <Kennzeichen> bei geändertem Arbeitsbaum hinzu (Standard: \"-dirty\")"
+
 #: builtin/describe.c:436
 msgid "--long is incompatible with --abbrev=0"
 msgstr "--long ist inkompatibel mit --abbrev=0"
@@ -2972,40 +4128,162 @@ msgstr "--dirty ist inkompatibel mit Versionen"
 msgid "'%s': not a regular file or symlink"
 msgstr "'%s': keine reguläre Datei oder symbolischer Link"
 
-#: builtin/diff.c:224
+#: builtin/diff.c:228
 #, c-format
 msgid "invalid option: %s"
 msgstr "Ungültige Option: %s"
 
-#: builtin/diff.c:301
+#: builtin/diff.c:305
 msgid "Not a git repository"
 msgstr "Kein Git-Projektarchiv"
 
-#: builtin/diff.c:344
+#: builtin/diff.c:348
 #, c-format
 msgid "invalid object '%s' given."
 msgstr "Objekt '%s' ist ungültig."
 
-#: builtin/diff.c:349
+#: builtin/diff.c:353
 #, c-format
 msgid "more than %d trees given: '%s'"
 msgstr "Mehr als %d Zweige angegeben: '%s'"
 
-#: builtin/diff.c:359
+#: builtin/diff.c:363
 #, c-format
 msgid "more than two blobs given: '%s'"
 msgstr "Mehr als zwei Blobs angegeben: '%s'"
 
-#: builtin/diff.c:367
+#: builtin/diff.c:371
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr "unbehandeltes Objekt '%s' angegeben"
 
-#: builtin/fetch.c:200
+#: builtin/fast-export.c:22
+msgid "git fast-export [rev-list-opts]"
+msgstr "git fast-export [rev-list-opts]"
+
+#: builtin/fast-export.c:635
+msgid "show progress after <n> objects"
+msgstr "zeigt Fortschritt nach <n> Objekten an"
+
+#: builtin/fast-export.c:637
+msgid "select handling of signed tags"
+msgstr "wählt Behandlung von signierten Markierungen"
+
+#: builtin/fast-export.c:640
+msgid "select handling of tags that tag filtered objects"
+msgstr "wählt Behandlung von Markierungen, die gefilterte Objekte markieren"
+
+#: builtin/fast-export.c:643
+msgid "Dump marks to this file"
+msgstr "Schreibt Kennzeichen in diese Datei"
+
+#: builtin/fast-export.c:645
+msgid "Import marks from this file"
+msgstr "Importiert Kennzeichen von dieser Datei"
+
+#: builtin/fast-export.c:647
+msgid "Fake a tagger when tags lack one"
+msgstr ""
+"erzeugt künstlich einen Markierungsersteller, wenn die Markierung keinen hat"
+
+#: builtin/fast-export.c:649
+msgid "Output full tree for each commit"
+msgstr "gibt für jede Version den gesamten Baum aus"
+
+#: builtin/fast-export.c:651
+msgid "Use the done feature to terminate the stream"
+msgstr "Benutzt die \"done\"-Funktion um den Strom abzuschließen"
+
+#: builtin/fast-export.c:652
+msgid "Skip output of blob data"
+msgstr "Überspringt Ausgabe von Blob-Daten"
+
+#: builtin/fetch.c:20
+msgid "git fetch [<options>] [<repository> [<refspec>...]]"
+msgstr "git fetch [<Optionen>] [<Projektarchiv> [<Referenzspezifikation>...]]"
+
+#: builtin/fetch.c:21
+msgid "git fetch [<options>] <group>"
+msgstr "git fetch [<Optionen>] <Gruppe>"
+
+#: builtin/fetch.c:22
+msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
+msgstr "git fetch --multiple [<Optionen>] [(<Projektarchiv> | <Gruppe>)...]"
+
+#: builtin/fetch.c:23
+msgid "git fetch --all [<options>]"
+msgstr "git fetch --all [<Optionen>]"
+
+#: builtin/fetch.c:60
+msgid "fetch from all remotes"
+msgstr "fordert von allen externen Projektarchiven an"
+
+#: builtin/fetch.c:62
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "hängt an .git/FETCH_HEAD an, anstatt zu überschreiben"
+
+#: builtin/fetch.c:64
+msgid "path to upload pack on remote end"
+msgstr "Pfad des Programms zum Hochladen von Paketen auf der Gegenseite"
+
+#: builtin/fetch.c:65
+msgid "force overwrite of local branch"
+msgstr "erzwingt das Überschreiben von lokalen Zweigen"
+
+#: builtin/fetch.c:67
+msgid "fetch from multiple remotes"
+msgstr "fordert von mehreren externen Projektarchiven an"
+
+#: builtin/fetch.c:69
+msgid "fetch all tags and associated objects"
+msgstr "fordert alle Markierungen und verbundene Objekte an"
+
+#: builtin/fetch.c:71
+msgid "do not fetch all tags (--no-tags)"
+msgstr "fordert nicht alle Markierungen an (--no-tags)"
+
+#: builtin/fetch.c:73
+msgid "prune remote-tracking branches no longer on remote"
+msgstr ""
+"entfernt externe Übernahmezweige, die sich nicht mehr im Fernarchiv befinden"
+
+#: builtin/fetch.c:74
+msgid "on-demand"
+msgstr "bei-Bedarf"
+
+#: builtin/fetch.c:75
+msgid "control recursive fetching of submodules"
+msgstr "kontrolliert rekursive Anforderungen von Unterprojekten"
+
+#: builtin/fetch.c:79
+msgid "keep downloaded pack"
+msgstr "behält heruntergeladenes Paket"
+
+#: builtin/fetch.c:81
+msgid "allow updating of HEAD ref"
+msgstr "erlaubt Aktualisierung der \"HEAD\"-Referenz"
+
+#: builtin/fetch.c:84
+msgid "deepen history of shallow clone"
+msgstr "vertieft die Historie eines flachen Klon"
+
+#: builtin/fetch.c:85 builtin/log.c:1088
+msgid "dir"
+msgstr "Verzeichnis"
+
+#: builtin/fetch.c:86
+msgid "prepend this to submodule path output"
+msgstr "stellt dies an die Ausgabe der Unterprojekt-Pfade voran"
+
+#: builtin/fetch.c:89
+msgid "default mode for recursion"
+msgstr "Standard-Modus für Rekursion"
+
+#: builtin/fetch.c:201
 msgid "Couldn't find remote ref HEAD"
 msgstr "Konnte externe Referenz der Zweigspitze (HEAD) nicht finden."
 
-#: builtin/fetch.c:253
+#: builtin/fetch.c:254
 #, c-format
 msgid "object %s not found"
 msgstr "Objekt %s nicht gefunden"
@@ -3077,7 +4355,7 @@ msgid ""
 " 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
 "Einige lokale Referenzen konnten nicht aktualisiert werden; versuche\n"
-"'git remote prune %s' um jeden älteren, widersprüchlichen Zweig zu entfernen."
+"'git remote prune %s' um jeden älteren, widersprüchlichen Zweig zu löschen."
 
 #: builtin/fetch.c:549
 #, c-format
@@ -3119,17 +4397,17 @@ msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s"
 msgid "Option \"%s\" is ignored for %s\n"
 msgstr "Option \"%s\" wird ignoriert für %s\n"
 
-#: builtin/fetch.c:888
+#: builtin/fetch.c:891
 #, c-format
 msgid "Fetching %s\n"
 msgstr "Fordere an von %s\n"
 
-#: builtin/fetch.c:890 builtin/remote.c:100
+#: builtin/fetch.c:893 builtin/remote.c:100
 #, c-format
 msgid "Could not fetch %s"
 msgstr "Konnte nicht von %s anfordern"
 
-#: builtin/fetch.c:907
+#: builtin/fetch.c:912
 msgid ""
 "No remote repository specified.  Please, specify either a URL or a\n"
 "remote name from which new revisions should be fetched."
@@ -3138,29 +4416,148 @@ msgstr ""
 "oder den Namen des externen Archivs an, von welchem neue\n"
 "Versionen angefordert werden sollen."
 
-#: builtin/fetch.c:927
+#: builtin/fetch.c:932
 msgid "You need to specify a tag name."
 msgstr "Du musst den Namen der Markierung angeben."
 
-#: builtin/fetch.c:979
+#: builtin/fetch.c:984
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all akzeptiert kein Projektarchiv als Argument"
 
-#: builtin/fetch.c:981
+#: builtin/fetch.c:986
 msgid "fetch --all does not make sense with refspecs"
 msgstr "fetch --all macht keinen Sinn mit Referenzspezifikationen"
 
-#: builtin/fetch.c:992
+#: builtin/fetch.c:997
 #, c-format
 msgid "No such remote or remote group: %s"
 msgstr "Kein externes Archiv (einzeln oder Gruppe): %s"
 
-#: builtin/fetch.c:1000
+#: builtin/fetch.c:1005
 msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr ""
 "Abholen einer Gruppe mit Angabe von Referenzspezifikationen macht keinen "
 "Sinn."
 
+#: builtin/fmt-merge-msg.c:13
+msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
+msgstr ""
+"git fmt-merge-msg [-m <Beschreibung>] [--log[=<n>]|--no-log] [--file <Datei>]"
+
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
+#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
+msgid "n"
+msgstr "Anzahl"
+
+#: builtin/fmt-merge-msg.c:654
+msgid "populate log with at most <n> entries from shortlog"
+msgstr "fügt Historie mit höchstens <n> Einträgen von \"shortlog\" hinzu"
+
+#: builtin/fmt-merge-msg.c:657
+msgid "alias for --log (deprecated)"
+msgstr "Alias für --log (veraltet)"
+
+#: builtin/fmt-merge-msg.c:660
+msgid "text"
+msgstr "Text"
+
+#: builtin/fmt-merge-msg.c:661
+msgid "use <text> as start of message"
+msgstr "benutzt <Text> als Beschreibungsanfang"
+
+#: builtin/fmt-merge-msg.c:662
+msgid "file to read from"
+msgstr "Datei zum Einlesen"
+
+#: builtin/for-each-ref.c:979
+msgid "git for-each-ref [options] [<pattern>]"
+msgstr "git for-each-ref [Optionen] [<Muster>]"
+
+#: builtin/for-each-ref.c:994
+msgid "quote placeholders suitably for shells"
+msgstr "formatiert Platzhalter als Shell-String"
+
+#: builtin/for-each-ref.c:996
+msgid "quote placeholders suitably for perl"
+msgstr "formatiert Platzhalter als Perl-String"
+
+#: builtin/for-each-ref.c:998
+msgid "quote placeholders suitably for python"
+msgstr "formatiert Platzhalter als Python-String"
+
+#: builtin/for-each-ref.c:1000
+msgid "quote placeholders suitably for tcl"
+msgstr "formatiert Platzhalter als TCL-String"
+
+#: builtin/for-each-ref.c:1003
+msgid "show only <n> matched refs"
+msgstr "zeigt nur <n> passende Referenzen"
+
+#: builtin/for-each-ref.c:1004
+msgid "format"
+msgstr "Format"
+
+#: builtin/for-each-ref.c:1004
+msgid "format to use for the output"
+msgstr "für die Ausgabe zu verwendendes Format"
+
+#: builtin/for-each-ref.c:1005
+msgid "key"
+msgstr "Schüssel"
+
+#: builtin/for-each-ref.c:1006
+msgid "field name to sort on"
+msgstr "sortiere nach diesem Feld"
+
+#: builtin/fsck.c:608
+msgid "git fsck [options] [<object>...]"
+msgstr "git fsck [Optionen] [<Objekt>...]"
+
+#: builtin/fsck.c:614
+msgid "show unreachable objects"
+msgstr "zeigt unerreichbare Objekte"
+
+#: builtin/fsck.c:615
+msgid "show dangling objects"
+msgstr "zeigt unreferenzierte Objekte"
+
+#: builtin/fsck.c:616
+msgid "report tags"
+msgstr "meldet Markierungen"
+
+#: builtin/fsck.c:617
+msgid "report root nodes"
+msgstr "meldet Hauptwurzeln"
+
+#: builtin/fsck.c:618
+msgid "make index objects head nodes"
+msgstr "erzeugt Kopfknoten der Bereitstellungsobjekte"
+
+#: builtin/fsck.c:619
+msgid "make reflogs head nodes (default)"
+msgstr "erzeugt Kopfknoten des Referenzprotokolls (Standard)"
+
+#: builtin/fsck.c:620
+msgid "also consider packs and alternate objects"
+msgstr ""
+
+#: builtin/fsck.c:621
+msgid "enable more strict checking"
+msgstr "aktiviert genauere Prüfung"
+
+#: builtin/fsck.c:623
+msgid "write dangling objects in .git/lost-found"
+msgstr "schreibt unreferenzierte Objekte nach .git/lost-found"
+
+#: builtin/fsck.c:624 builtin/prune.c:134
+msgid "show progress"
+msgstr "zeigt Fortschrittsanzeige"
+
+#: builtin/gc.c:22
+msgid "git gc [options]"
+msgstr "git gc [Optionen]"
+
 #: builtin/gc.c:63
 #, c-format
 msgid "Invalid %s: '%s'"
@@ -3171,14 +4568,19 @@ msgstr "Ungültiger %s: '%s'"
 msgid "insanely long object directory %.*s"
 msgstr "zu langes Objekt-Verzeichnis %.*s"
 
-#: builtin/gc.c:221
-#, c-format
-msgid "Auto packing the repository for optimum performance.\n"
-msgstr ""
-"Die Datenbank des Projektarchivs wird für eine optimale Performance "
-"komprimiert.\n"
+#: builtin/gc.c:179
+msgid "prune unreferenced objects"
+msgstr "entfernt unreferenzierte Objekte"
+
+#: builtin/gc.c:181
+msgid "be more thorough (increased runtime)"
+msgstr "mehr Gründlichkeit (erhöht Laufzeit)"
+
+#: builtin/gc.c:182
+msgid "enable auto-gc mode"
+msgstr "aktiviert \"auto-gc\" Modus"
 
-#: builtin/gc.c:224
+#: builtin/gc.c:222
 #, c-format
 msgid ""
 "Auto packing the repository for optimum performance. You may also\n"
@@ -3188,73 +4590,304 @@ msgstr ""
 "komprimiert. Du kannst auch \"git gc\" manuell ausführen.\n"
 "Siehe \"git help gc\" für weitere Informationen.\n"
 
-#: builtin/gc.c:251
+#: builtin/gc.c:249
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
 "Es gibt zu viele unerreichbare lose Objekte; führe 'git prune' aus, um diese "
-"zu entfernen."
+"zu löschen."
 
-#: builtin/grep.c:216
+#: builtin/grep.c:22
+msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
+msgstr "git grep [Optionen] [-e] <Muster> [<Version>...] [[--] <Pfad>...]"
+
+#: builtin/grep.c:217
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep: Fehler beim Erzeugen eines Thread: %s"
 
-#: builtin/grep.c:454
+#: builtin/grep.c:365
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Fehler beim Verzeichniswechsel: %s"
 
-#: builtin/grep.c:530 builtin/grep.c:564
+#: builtin/grep.c:443 builtin/grep.c:478
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "konnte Zweig (%s) nicht lesen"
 
-#: builtin/grep.c:578
+#: builtin/grep.c:493
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "kann \"grep\" nicht mit Objekten des Typs %s durchführen"
 
-#: builtin/grep.c:636
+#: builtin/grep.c:551
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "Schalter '%c' erwartet einen numerischen Wert"
 
-#: builtin/grep.c:653
+#: builtin/grep.c:568
 #, c-format
 msgid "cannot open '%s'"
 msgstr "kann '%s' nicht öffnen"
 
-#: builtin/grep.c:917
+#: builtin/grep.c:643
+msgid "search in index instead of in the work tree"
+msgstr "sucht in der Bereitstellung anstatt im Arbeitsbaum"
+
+#: builtin/grep.c:645
+msgid "find in contents not managed by git"
+msgstr "findet auch in Inhalten, die nicht von Git verwaltet werden"
+
+#: builtin/grep.c:647
+msgid "search in both tracked and untracked files"
+msgstr "sucht in beobachteten und unbeobachteten Dateien"
+
+#: builtin/grep.c:649
+msgid "search also in ignored files"
+msgstr "sucht auch in ignorierten Dateien"
+
+#: builtin/grep.c:652
+msgid "show non-matching lines"
+msgstr "zeigt Zeilen ohne Übereinstimmungen"
+
+#: builtin/grep.c:654
+msgid "case insensitive matching"
+msgstr "findet Übereinstimmungen unabhängig von Groß- und Kleinschreibung"
+
+#: builtin/grep.c:656
+msgid "match patterns only at word boundaries"
+msgstr "sucht nur ganze Wörter"
+
+#: builtin/grep.c:658
+msgid "process binary files as text"
+msgstr "verarbeitet binäre Dateien als Text"
+
+#: builtin/grep.c:660
+msgid "don't match patterns in binary files"
+msgstr "findet keine Muster in Binärdateien"
+
+#: builtin/grep.c:663
+msgid "descend at most <depth> levels"
+msgstr "durchläuft höchstens <Tiefe> Ebenen"
+
+#: builtin/grep.c:667
+msgid "use extended POSIX regular expressions"
+msgstr "benutzt erweiterte reguläre Ausdrücke aus POSIX"
+
+#: builtin/grep.c:670
+msgid "use basic POSIX regular expressions (default)"
+msgstr "benutzt grundlegende reguläre Ausdrücke aus POSIX (Standard)"
+
+#: builtin/grep.c:673
+msgid "interpret patterns as fixed strings"
+msgstr "interpretiert Muster als feste Zeichenketten"
+
+#: builtin/grep.c:676
+msgid "use Perl-compatible regular expressions"
+msgstr "benutzt Perl-kompatible reguläre Ausdrücke"
+
+#: builtin/grep.c:679
+msgid "show line numbers"
+msgstr "zeigt Zeilennummern"
+
+#: builtin/grep.c:680
+msgid "don't show filenames"
+msgstr "zeigt keine Dateinamen"
+
+#: builtin/grep.c:681
+msgid "show filenames"
+msgstr "zeigt Dateinamen"
+
+#: builtin/grep.c:683
+msgid "show filenames relative to top directory"
+msgstr "zeigt Dateinamen relativ zum Projektverzeichnis"
+
+#: builtin/grep.c:685
+msgid "show only filenames instead of matching lines"
+msgstr "zeigt nur Dateinamen anstatt übereinstimmende Zeilen"
+
+#: builtin/grep.c:687
+msgid "synonym for --files-with-matches"
+msgstr "Synonym für --files-with-matches"
+
+#: builtin/grep.c:690
+msgid "show only the names of files without match"
+msgstr "zeigt nur die Dateinamen ohne Übereinstimmungen"
+
+#: builtin/grep.c:692
+msgid "print NUL after filenames"
+msgstr "gibt NUL-Zeichen nach Dateinamen aus"
+
+#: builtin/grep.c:694
+msgid "show the number of matches instead of matching lines"
+msgstr "zeigt, anstatt der Zeilen, die Anzahl der übereinstimmenden Zeilen"
+
+#: builtin/grep.c:695
+msgid "highlight matches"
+msgstr "hebt Übereinstimmungen hervor"
+
+#: builtin/grep.c:697
+msgid "print empty line between matches from different files"
+msgstr ""
+"gibt eine Leerzeile zwischen Übereinstimmungen in verschiedenen Dateien aus"
+
+#: builtin/grep.c:699
+msgid "show filename only once above matches from same file"
+msgstr ""
+"zeigt den Dateinamen nur einmal oberhalb der Übereinstimmungen aus dieser "
+"Datei an"
+
+#: builtin/grep.c:702
+msgid "show <n> context lines before and after matches"
+msgstr "zeigt <n> Zeilen vor und nach den Übereinstimmungen an"
+
+#: builtin/grep.c:705
+msgid "show <n> context lines before matches"
+msgstr "zeigt <n> Zeilen vor den Übereinstimmungen an"
+
+#: builtin/grep.c:707
+msgid "show <n> context lines after matches"
+msgstr "zeigt <n> Zeilen nach den Übereinstimmungen an"
+
+#: builtin/grep.c:708
+msgid "shortcut for -C NUM"
+msgstr "Kurzform für -C NUM"
+
+#: builtin/grep.c:711
+msgid "show a line with the function name before matches"
+msgstr "zeigt eine Zeile mit dem Funktionsnamen vor Übereinstimmungen an"
+
+#: builtin/grep.c:713
+msgid "show the surrounding function"
+msgstr "zeigt die umgebende Funktion an"
+
+#: builtin/grep.c:716
+msgid "read patterns from file"
+msgstr "liest Muster von einer Datei"
+
+#: builtin/grep.c:718
+msgid "match <pattern>"
+msgstr "findet <Muster>"
+
+#: builtin/grep.c:720
+msgid "combine patterns specified with -e"
+msgstr "kombiniert Muster, die mit -e angegeben wurden"
+
+#: builtin/grep.c:732
+msgid "indicate hit with exit status without output"
+msgstr "zeigt Übereinstimmungen nur durch Beendigungsstatus an"
+
+#: builtin/grep.c:734
+msgid "show only matches from files that match all patterns"
+msgstr "zeigt nur Übereinstimmungen von Dateien, die allen Mustern entsprechen"
+
+#: builtin/grep.c:736
+msgid "show parse tree for grep expression"
+msgstr "zeigt geparsten Baum für \"grep\"-Ausdruck"
+
+#: builtin/grep.c:740
+msgid "pager"
+msgstr "Anzeigeprogramm"
+
+#: builtin/grep.c:740
+msgid "show matching files in the pager"
+msgstr "zeigt Dateien mit Übereinstimmungen im Anzeigeprogramm"
+
+#: builtin/grep.c:743
+msgid "allow calling of grep(1) (ignored by this build)"
+msgstr "erlaubt den Aufruf von grep(1) (von dieser Programmversion ignoriert)"
+
+#: builtin/grep.c:744 builtin/show-ref.c:184
+msgid "show usage"
+msgstr "zeigt Verwendung"
+
+#: builtin/grep.c:811
 msgid "no pattern given."
 msgstr "keine Muster angegeben"
 
-#: builtin/grep.c:931
+#: builtin/grep.c:825
 #, c-format
 msgid "bad object %s"
 msgstr "ungültiges Objekt %s"
 
-#: builtin/grep.c:972
+#: builtin/grep.c:866
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager arbeitet nur innerhalb des Arbeitsbaums"
 
-#: builtin/grep.c:995
+#: builtin/grep.c:889
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached oder --untracked kann nicht mit --no-index benutzt werden"
 
-#: builtin/grep.c:1000
+#: builtin/grep.c:894
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr "--no-index oder --untracked kann nicht mit Versionen benutzt werden"
 
-#: builtin/grep.c:1003
+#: builtin/grep.c:897
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr ""
 "--[no-]exlude-standard kann nicht mit beobachteten Inhalten benutzt werden"
 
-#: builtin/grep.c:1011
+#: builtin/grep.c:905
 msgid "both --cached and trees are given."
 msgstr "sowohl --cached als auch Zweige gegeben"
 
+#: builtin/hash-object.c:60
+msgid ""
+"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
+"<file>..."
+msgstr ""
+"git hash-object [-t <Art>] [-w] [--path=<Datei>|--no-filters] [--stdin] [--] "
+"<Datei>..."
+
+#: builtin/hash-object.c:61
+msgid "git hash-object  --stdin-paths < <list-of-paths>"
+msgstr "git hash-object  --stdin-paths < <Liste-von-Pfaden>"
+
+#: builtin/hash-object.c:72
+msgid "type"
+msgstr "Art"
+
+#: builtin/hash-object.c:72
+msgid "object type"
+msgstr "Art des Objektes"
+
+#: builtin/hash-object.c:73
+msgid "write the object into the object database"
+msgstr "schreibt das Objekt in die Objektdatenbank"
+
+#: builtin/hash-object.c:74
+msgid "read the object from stdin"
+msgstr "liest das Objekt von der Standard-Eingabe"
+
+#: builtin/hash-object.c:76
+msgid "store file as is without filters"
+msgstr "speichert Datei wie sie ist, ohne Filter"
+
+#: builtin/hash-object.c:77
+msgid "process file as it were from this path"
+msgstr "verarbeitet Datei, als ob sie von diesem Pfad wäre"
+
+#: builtin/help.c:43
+msgid "print all available commands"
+msgstr "Anzeige aller vorhandenen Kommandos"
+
+#: builtin/help.c:44
+msgid "show man page"
+msgstr "zeigt Handbuch"
+
+#: builtin/help.c:45
+msgid "show manual in web browser"
+msgstr "zeigt Handbuch in einem Webbrowser"
+
+#: builtin/help.c:47
+msgid "show info page"
+msgstr "zeigt Info-Seite"
+
+#: builtin/help.c:53
+msgid "git help [--all] [--man|--web|--info] [command]"
+msgstr "git help [--all] [--man|--web|--info] [Kommando]"
+
 #: builtin/help.c:65
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -3369,6 +5002,11 @@ msgstr "Kann Paketdatei '%s' nicht öffnen"
 msgid "pack signature mismatch"
 msgstr "Paketsignatur stimmt nicht überein"
 
+#: builtin/index-pack.c:294
+#, c-format
+msgid "pack version %<PRIu32> unsupported"
+msgstr "Paketversion %<PRIu32> nicht unterstützt"
+
 #: builtin/index-pack.c:312
 #, c-format
 msgid "pack has bad object at offset %lu: %s"
@@ -3476,93 +5114,123 @@ msgstr "Fehler beim Ausführen von \"parse_pack_objects()\""
 msgid "Resolving deltas"
 msgstr "Löse Unterschiede auf"
 
-#: builtin/index-pack.c:1105
+#: builtin/index-pack.c:1064
+#, c-format
+msgid "unable to create thread: %s"
+msgstr "kann Thread nicht erzeugen: %s"
+
+#: builtin/index-pack.c:1106
 msgid "confusion beyond insanity"
 msgstr "Fehler beim Auflösen der Unterschiede"
 
-#: builtin/index-pack.c:1124
+#: builtin/index-pack.c:1112
+#, c-format
+msgid "completed with %d local objects"
+msgstr "vervollständigt mit %d lokalen Objekten"
+
+#: builtin/index-pack.c:1121
+#, c-format
+msgid "Unexpected tail checksum for %s (disk corruption?)"
+msgstr "Unerwartete Prüfsumme für %s (Festplattenfehler?)"
+
+#: builtin/index-pack.c:1125
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
 msgstr[0] "Paket hat %d unaufgelöste Unterschied"
 msgstr[1] "Paket hat %d unaufgelöste Unterschiede"
 
-#: builtin/index-pack.c:1149
+#: builtin/index-pack.c:1150
 #, c-format
 msgid "unable to deflate appended object (%d)"
 msgstr "Konnte angehängtes Objekt (%d) nicht komprimieren"
 
-#: builtin/index-pack.c:1228
+#: builtin/index-pack.c:1229
 #, c-format
 msgid "local object %s is corrupt"
 msgstr "lokales Objekt %s ist beschädigt"
 
-#: builtin/index-pack.c:1252
+#: builtin/index-pack.c:1253
 msgid "error while closing pack file"
 msgstr "Fehler beim Schließen der Paketdatei"
 
-#: builtin/index-pack.c:1265
+#: builtin/index-pack.c:1266
 #, c-format
 msgid "cannot write keep file '%s'"
 msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben"
 
-#: builtin/index-pack.c:1273
+#: builtin/index-pack.c:1274
 #, c-format
 msgid "cannot close written keep file '%s'"
 msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen"
 
-#: builtin/index-pack.c:1286
+#: builtin/index-pack.c:1287
 msgid "cannot store pack file"
 msgstr "Kann Paketdatei nicht speichern"
 
-#: builtin/index-pack.c:1297
+#: builtin/index-pack.c:1298
 msgid "cannot store index file"
 msgstr "Kann Indexdatei nicht speichern"
 
-#: builtin/index-pack.c:1398
+#: builtin/index-pack.c:1331
+#, c-format
+msgid "bad pack.indexversion=%<PRIu32>"
+msgstr "\"pack.indexversion=%<PRIu32>\" ist ungültig"
+
+#: builtin/index-pack.c:1337
+#, c-format
+msgid "invalid number of threads specified (%d)"
+msgstr "ungültige Anzahl von Threads angegeben (%d)"
+
+#: builtin/index-pack.c:1341 builtin/index-pack.c:1514
+#, c-format
+msgid "no threads support, ignoring %s"
+msgstr "keine Unterstützung von Threads, '%s' wird ignoriert"
+
+#: builtin/index-pack.c:1399
 #, c-format
 msgid "Cannot open existing pack file '%s'"
 msgstr "Kann existierende Paketdatei '%s' nicht öffnen"
 
-#: builtin/index-pack.c:1400
+#: builtin/index-pack.c:1401
 #, c-format
 msgid "Cannot open existing pack idx file for '%s'"
 msgstr "Kann existierende Indexdatei für Paket '%s' nicht öffnen"
 
-#: builtin/index-pack.c:1447
+#: builtin/index-pack.c:1448
 #, c-format
 msgid "non delta: %d object"
 msgid_plural "non delta: %d objects"
 msgstr[0] "kein Unterschied: %d Objekt"
 msgstr[1] "kein Unterschied: %d Objekte"
 
-#: builtin/index-pack.c:1454
+#: builtin/index-pack.c:1455
 #, c-format
 msgid "chain length = %d: %lu object"
 msgid_plural "chain length = %d: %lu objects"
 msgstr[0] "Länge der Objekt-Liste = %d: %lu Objekt"
 msgstr[1] "Länge der Objekt-Liste = %d: %lu Objekte"
 
-#: builtin/index-pack.c:1481
+#: builtin/index-pack.c:1482
 msgid "Cannot come back to cwd"
 msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln"
 
-#: builtin/index-pack.c:1525 builtin/index-pack.c:1528
-#: builtin/index-pack.c:1540 builtin/index-pack.c:1544
+#: builtin/index-pack.c:1526 builtin/index-pack.c:1529
+#: builtin/index-pack.c:1541 builtin/index-pack.c:1545
 #, c-format
 msgid "bad %s"
 msgstr "%s ist ungültig"
 
-#: builtin/index-pack.c:1558
+#: builtin/index-pack.c:1559
 msgid "--fix-thin cannot be used without --stdin"
 msgstr "--fix-thin kann nicht ohne --stdin benutzt werden"
 
-#: builtin/index-pack.c:1562 builtin/index-pack.c:1572
+#: builtin/index-pack.c:1563 builtin/index-pack.c:1573
 #, c-format
 msgid "packfile name '%s' does not end with '.pack'"
 msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'"
 
-#: builtin/index-pack.c:1581
+#: builtin/index-pack.c:1582
 msgid "--verify with no packfile name given"
 msgstr "--verify ohne Name der Paketdatei angegeben"
 
@@ -3682,6 +5350,27 @@ msgstr " gemeinsames"
 msgid "cannot tell cwd"
 msgstr "kann aktuelles Arbeitsverzeichnis nicht ermitteln"
 
+#: builtin/init-db.c:467
+msgid ""
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared"
+"[=<permissions>]] [directory]"
+msgstr ""
+"git init [-q | --quiet] [--bare] [--template=<Vorlagenverzeichnis>] [--shared"
+"[=<Berechtigungen>]] [Verzeichnis]"
+
+#: builtin/init-db.c:490
+msgid "permissions"
+msgstr "Berechtigungen"
+
+#: builtin/init-db.c:491
+msgid "specify that the git repository is to be shared amongst several users"
+msgstr ""
+"gibt an, dass das Git-Projektarchiv mit mehreren Benutzern geteilt wird"
+
+#: builtin/init-db.c:493 builtin/prune-packed.c:77
+msgid "be quiet"
+msgstr "weniger Ausgaben"
+
 #: builtin/init-db.c:522 builtin/init-db.c:529
 #, c-format
 msgid "cannot mkdir %s"
@@ -3710,105 +5399,396 @@ msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen."
 msgid "Cannot access work tree '%s'"
 msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen."
 
+#: builtin/log.c:37
+msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
+msgstr "git log [<Optionen>] [<seit>..<bis>] [[--] <Pfad>...]\n"
+
+#: builtin/log.c:38
+msgid "   or: git show [options] <object>..."
+msgstr "   oder: git show [Optionen] <Objekt>..."
+
+#: builtin/log.c:100
+msgid "suppress diff output"
+msgstr "unterdrückt Ausgabe der Unterschiede"
+
+#: builtin/log.c:101
+msgid "show source"
+msgstr "zeigt Quelle"
+
+#: builtin/log.c:102
+msgid "decorate options"
+msgstr "decorate-Optionen"
+
 #: builtin/log.c:189
 #, c-format
 msgid "Final output: %d %s\n"
 msgstr "letzte Ausgabe: %d %s\n"
 
-#: builtin/log.c:403 builtin/log.c:494
+#: builtin/log.c:405 builtin/log.c:497
 #, c-format
 msgid "Could not read object %s"
 msgstr "Kann Objekt %s nicht lesen."
 
-#: builtin/log.c:518
+#: builtin/log.c:521
 #, c-format
 msgid "Unknown type: %d"
 msgstr "Unbekannter Typ: %d"
 
-#: builtin/log.c:608
+#: builtin/log.c:613
 msgid "format.headers without value"
 msgstr "format.headers ohne Wert"
 
-#: builtin/log.c:682
+#: builtin/log.c:687
 msgid "name of output directory is too long"
 msgstr "Name des Ausgabeverzeichnisses ist zu lang."
 
-#: builtin/log.c:693
+#: builtin/log.c:698
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr "Kann Patch-Datei %s nicht öffnen"
 
-#: builtin/log.c:707
+#: builtin/log.c:712
 msgid "Need exactly one range."
 msgstr "Brauche genau einen Versionsbereich."
 
-#: builtin/log.c:715
+#: builtin/log.c:720
 msgid "Not a range."
 msgstr "Kein Versionsbereich."
 
-#: builtin/log.c:789
+#: builtin/log.c:794
 msgid "Cover letter needs email format"
 msgstr "Anschreiben benötigt E-Mail-Format"
 
-#: builtin/log.c:862
+#: builtin/log.c:867
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "ungültiges in-reply-to: %s"
 
-#: builtin/log.c:935
+#: builtin/log.c:895
+msgid "git format-patch [options] [<since> | <revision range>]"
+msgstr "git format-patch [Optionen] [<seit> | <Versionsbereich>]"
+
+#: builtin/log.c:940
 msgid "Two output directories?"
 msgstr "Zwei Ausgabeverzeichnisse?"
 
-#: builtin/log.c:1157
+#: builtin/log.c:1068
+msgid "use [PATCH n/m] even with a single patch"
+msgstr "benutzt [PATCH n/m] auch mit einzelnem Patch"
+
+#: builtin/log.c:1071
+msgid "use [PATCH] even with multiple patches"
+msgstr "benutzt [PATCH] auch mit mehreren Patches"
+
+#: builtin/log.c:1075
+msgid "print patches to standard out"
+msgstr "Ausgabe der Patches in Standard-Ausgabe"
+
+#: builtin/log.c:1077
+msgid "generate a cover letter"
+msgstr "erzeugt ein Deckblatt"
+
+#: builtin/log.c:1079
+msgid "use simple number sequence for output file names"
+msgstr "benutzt einfache Nummernfolge für die Namen der Ausgabedateien"
+
+#: builtin/log.c:1080
+msgid "sfx"
+msgstr "Dateiendung"
+
+#: builtin/log.c:1081
+msgid "use <sfx> instead of '.patch'"
+msgstr "verwendet <Dateiendung> anstatt '.patch'"
+
+#: builtin/log.c:1083
+msgid "start numbering patches at <n> instead of 1"
+msgstr "beginnt die Nummerierung der Patches bei <n> anstatt bei 1"
+
+#: builtin/log.c:1085
+msgid "Use [<prefix>] instead of [PATCH]"
+msgstr "benutzt [<Prefix>] anstatt [PATCH]"
+
+#: builtin/log.c:1088
+msgid "store resulting files in <dir>"
+msgstr "speichert erzeugte Dateien in <Verzeichnis>"
+
+#: builtin/log.c:1091
+msgid "don't strip/add [PATCH]"
+msgstr "[PATCH] wird nicht entfernt/hinzugefügt"
+
+#: builtin/log.c:1094
+msgid "don't output binary diffs"
+msgstr "gibt keine binären Unterschiede aus"
+
+#: builtin/log.c:1096
+msgid "don't include a patch matching a commit upstream"
+msgstr ""
+"schließt keine Patches ein, die einer Version im Übernahmezweig entsprechen"
+
+#: builtin/log.c:1098
+msgid "show patch format instead of default (patch + stat)"
+msgstr "zeigt Patchformat anstatt des Standards (Patch + Zusammenfassung)"
+
+#: builtin/log.c:1100
+msgid "Messaging"
+msgstr "Email-Einstellungen"
+
+#: builtin/log.c:1101
+msgid "header"
+msgstr "Header"
+
+#: builtin/log.c:1102
+msgid "add email header"
+msgstr "fügt Email-Header hinzu"
+
+#: builtin/log.c:1103 builtin/log.c:1105
+msgid "email"
+msgstr "Email"
+
+#: builtin/log.c:1103
+msgid "add To: header"
+msgstr "fügt  \"To:\"-Header hinzu"
+
+#: builtin/log.c:1105
+msgid "add Cc: header"
+msgstr "fügt \"Cc:\"-Header hinzu"
+
+#: builtin/log.c:1107
+msgid "message-id"
+msgstr "message-id"
+
+#: builtin/log.c:1108
+msgid "make first mail a reply to <message-id>"
+msgstr "macht aus erster Email eine Antwort zu <message-id>"
+
+#: builtin/log.c:1109 builtin/log.c:1112
+msgid "boundary"
+msgstr "Grenze"
+
+#: builtin/log.c:1110
+msgid "attach the patch"
+msgstr "hängt einen Patch an"
+
+#: builtin/log.c:1113
+msgid "inline the patch"
+msgstr "fügt den Patch direkt in die Nachricht ein"
+
+#: builtin/log.c:1117
+msgid "enable message threading, styles: shallow, deep"
+msgstr "aktiviert Nachrichtenverkettung, Stile: shallow, deep"
+
+#: builtin/log.c:1119
+msgid "signature"
+msgstr "Signatur"
+
+#: builtin/log.c:1120
+msgid "add a signature"
+msgstr "fügt eine Signatur hinzu"
+
+#: builtin/log.c:1122
+msgid "don't print the patch filenames"
+msgstr "zeigt keine Dateinamen der Patches"
+
+#: builtin/log.c:1163
 #, c-format
 msgid "bogus committer info %s"
 msgstr "unechte Einreicher-Informationen %s"
 
-#: builtin/log.c:1202
+#: builtin/log.c:1208
 msgid "-n and -k are mutually exclusive."
 msgstr "-n und -k schließen sich gegenseitig aus"
 
-#: builtin/log.c:1204
+#: builtin/log.c:1210
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr "--subject-prefix und -k schließen sich gegenseitig aus"
 
-#: builtin/log.c:1212
-msgid "--name-only does not make sense"
-msgstr "--name-only macht keinen Sinn"
+#: builtin/log.c:1218
+msgid "--name-only does not make sense"
+msgstr "--name-only macht keinen Sinn"
+
+#: builtin/log.c:1220
+msgid "--name-status does not make sense"
+msgstr "--name-status macht keinen Sinn"
+
+#: builtin/log.c:1222
+msgid "--check does not make sense"
+msgstr "--check macht keinen Sinn"
+
+#: builtin/log.c:1245
+msgid "standard output, or directory, which one?"
+msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?"
+
+#: builtin/log.c:1247
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr "Konnte Verzeichnis '%s' nicht erstellen."
+
+#: builtin/log.c:1400
+msgid "Failed to create output files"
+msgstr "Fehler beim Erstellen der Ausgabedateien."
+
+#: builtin/log.c:1449
+msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
+msgstr "git cherry [-v] [<Übernahmezweig> [<Arbeitszweig> [<Limit>]]]"
+
+#: builtin/log.c:1504
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr ""
+"Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell "
+"an.\n"
+
+#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531
+#, c-format
+msgid "Unknown commit %s"
+msgstr "Unbekannte Version %s"
+
+#: builtin/ls-files.c:408
+msgid "git ls-files [options] [<file>...]"
+msgstr "git ls-files [Optionen] [<Datei>...]"
+
+#: builtin/ls-files.c:463
+msgid "identify the file status with tags"
+msgstr "zeigt den Dateistatus mit Markierungen"
+
+#: builtin/ls-files.c:465
+msgid "use lowercase letters for 'assume unchanged' files"
+msgstr "benutzt Kleinbuchstaben für Dateien mit 'assume unchanged' Markierung"
+
+#: builtin/ls-files.c:467
+msgid "show cached files in the output (default)"
+msgstr "zeigt zwischengespeicherten Dateien in der Ausgabe an (Standard)"
+
+#: builtin/ls-files.c:469
+msgid "show deleted files in the output"
+msgstr "zeigt entfernte Dateien in der Ausgabe an"
+
+#: builtin/ls-files.c:471
+msgid "show modified files in the output"
+msgstr "zeigt geänderte Dateien in der Ausgabe an"
+
+#: builtin/ls-files.c:473
+msgid "show other files in the output"
+msgstr "zeigt sonstige Dateien in der Ausgabe an"
+
+#: builtin/ls-files.c:475
+msgid "show ignored files in the output"
+msgstr "zeigt ignorierte Dateien in der Ausgabe an"
+
+#: builtin/ls-files.c:478
+msgid "show staged contents' object name in the output"
+msgstr "zeigt Objektnamen von Inhalten in der Bereitstellung in der Ausgabe an"
+
+#: builtin/ls-files.c:480
+msgid "show files on the filesystem that need to be removed"
+msgstr "zeigt Dateien im Dateisystem, die gelöscht werden müssen, an"
+
+#: builtin/ls-files.c:482
+msgid "show 'other' directories' name only"
+msgstr "zeigt nur Namen von 'sonstigen' Verzeichnissen an"
+
+#: builtin/ls-files.c:485
+msgid "don't show empty directories"
+msgstr "zeigt keine leeren Verzeichnisse an"
+
+#: builtin/ls-files.c:488
+msgid "show unmerged files in the output"
+msgstr "zeigt nicht zusammengeführte Dateien in der Ausgabe an"
+
+#: builtin/ls-files.c:490
+msgid "show resolve-undo information"
+msgstr "zeigt 'resolve-undo' Informationen an"
+
+#: builtin/ls-files.c:492
+msgid "skip files matching pattern"
+msgstr "lässt Dateien aus, die einem Muster entsprechen"
+
+#: builtin/ls-files.c:495
+msgid "exclude patterns are read from <file>"
+msgstr "schließt Muster, gelesen von <Datei>, aus"
+
+#: builtin/ls-files.c:498
+msgid "read additional per-directory exclude patterns in <file>"
+msgstr "liest zusätzliche pro-Verzeichnis Auschlussmuster aus <Datei>"
+
+#: builtin/ls-files.c:500
+msgid "add the standard git exclusions"
+msgstr "fügt die standardmäßigen Git-Ausschlüsse hinzu"
+
+#: builtin/ls-files.c:503
+msgid "make the output relative to the project top directory"
+msgstr "Ausgabe relativ zum Projektverzeichnis"
+
+#: builtin/ls-files.c:506
+msgid "if any <file> is not in the index, treat this as an error"
+msgstr ""
+"behandle es als Fehler, wenn sich eine <Datei> nicht in der Bereitstellung "
+"befindet"
+
+#: builtin/ls-files.c:507
+msgid "tree-ish"
+msgstr "Versionsreferenz"
+
+#: builtin/ls-files.c:508
+msgid "pretend that paths removed since <tree-ish> are still present"
+msgstr ""
+"gibt vor, dass Pfade, die seit <Versionsreferenz> gelöscht wurden, immer "
+"noch vorhanden sind"
+
+#: builtin/ls-files.c:510
+msgid "show debugging data"
+msgstr "zeigt Ausgaben zur Fehlersuche an"
+
+#: builtin/ls-tree.c:27
+msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
+msgstr "git ls-tree [<Optionen>] <Versionsreferenz> [<Pfad>...]"
+
+#: builtin/ls-tree.c:125
+msgid "only show trees"
+msgstr "zeigt nur Bäume an"
+
+#: builtin/ls-tree.c:127
+msgid "recurse into subtrees"
+msgstr "führt Rekursion in Teilbäumen durch"
 
-#: builtin/log.c:1214
-msgid "--name-status does not make sense"
-msgstr "--name-status macht keinen Sinn"
+#: builtin/ls-tree.c:129
+msgid "show trees when recursing"
+msgstr "zeigt Bäume bei Rekursion an"
 
-#: builtin/log.c:1216
-msgid "--check does not make sense"
-msgstr "--check macht keinen Sinn"
+#: builtin/ls-tree.c:132
+msgid "terminate entries with NUL byte"
+msgstr "schließt Einträge mit NUL-Byte ab"
 
-#: builtin/log.c:1239
-msgid "standard output, or directory, which one?"
-msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?"
+#: builtin/ls-tree.c:133
+msgid "include object size"
+msgstr "schließt Objektgröße ein"
 
-#: builtin/log.c:1241
-#, c-format
-msgid "Could not create directory '%s'"
-msgstr "Konnte Verzeichnis '%s' nicht erstellen."
+#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
+msgid "list only filenames"
+msgstr "listet nur Dateinamen auf"
 
-#: builtin/log.c:1394
-msgid "Failed to create output files"
-msgstr "Fehler beim Erstellen der Ausgabedateien."
+#: builtin/ls-tree.c:140
+msgid "use full path names"
+msgstr "benutzt vollständige Pfadnamen"
 
-#: builtin/log.c:1498
-#, c-format
-msgid ""
-"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+#: builtin/ls-tree.c:142
+msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
-"Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell "
-"an.\n"
+"listet den gesamten Baum auf; nicht nur das aktuelle Verzeichnis (impliziert "
+"--full-name)"
 
-#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
-#, c-format
-msgid "Unknown commit %s"
-msgstr "Unbekannte Version %s"
+#: builtin/merge.c:43
+msgid "git merge [options] [<commit>...]"
+msgstr "git merge [Optionen] [<Version>...]"
+
+#: builtin/merge.c:44
+msgid "git merge [options] <msg> HEAD <commit>"
+msgstr "git merge [Optionen] <Beschreibung> HEAD <Version>"
+
+#: builtin/merge.c:45
+msgid "git merge --abort"
+msgstr "git merge --abort"
 
 #: builtin/merge.c:90
 msgid "switch `m' requires a value"
@@ -3829,6 +5809,75 @@ msgstr "Verfügbare Strategien sind:"
 msgid "Available custom strategies are:"
 msgstr "Verfügbare benutzerdefinierte Strategien sind:"
 
+#: builtin/merge.c:183
+msgid "do not show a diffstat at the end of the merge"
+msgstr ""
+"zeigt keine Zusammenfassung der Unterschiede am Schluss der Zusammenführung "
+"an"
+
+#: builtin/merge.c:186
+msgid "show a diffstat at the end of the merge"
+msgstr ""
+"zeigt eine Zusammenfassung der Unterschiede am Schluss der Zusammenführung an"
+
+#: builtin/merge.c:187
+msgid "(synonym to --stat)"
+msgstr "(Synonym für --stat)"
+
+#: builtin/merge.c:189
+msgid "add (at most <n>) entries from shortlog to merge commit message"
+msgstr ""
+"fügt (höchstens <n>) Einträge von \"shortlog\" zur Beschreibung der "
+"Zusammenführung hinzu"
+
+#: builtin/merge.c:192
+msgid "create a single commit instead of doing a merge"
+msgstr "erzeugt eine einzelne Version anstatt einer Zusammenführung"
+
+#: builtin/merge.c:194
+msgid "perform a commit if the merge succeeds (default)"
+msgstr ""
+"führt eine Eintragung durch, wenn die Zusammenführung erfolgreich war "
+"(Standard)"
+
+#: builtin/merge.c:196
+msgid "edit message before committing"
+msgstr "Bearbeitung der Versionsbeschreibung vor der Eintragung"
+
+#: builtin/merge.c:198
+msgid "allow fast-forward (default)"
+msgstr "erlaubt Vorspulen (Standard)"
+
+#: builtin/merge.c:200
+msgid "abort if fast-forward is not possible"
+msgstr "bricht ab, wenn kein Vorspulen möglich ist"
+
+#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112
+msgid "strategy"
+msgstr "Strategie"
+
+#: builtin/merge.c:203
+msgid "merge strategy to use"
+msgstr "zu verwendende Zusammenführungsstrategie"
+
+#: builtin/merge.c:204
+msgid "option=value"
+msgstr "Option=Wert"
+
+#: builtin/merge.c:205
+msgid "option for selected merge strategy"
+msgstr "Option für ausgewählte Zusammenführungsstrategie"
+
+#: builtin/merge.c:207
+msgid "merge commit message (for a non-fast-forward merge)"
+msgstr ""
+"führt Versionsbeschreibung zusammen (für eine Zusammenführung, die kein "
+"Vorspulen war)"
+
+#: builtin/merge.c:211
+msgid "abort the current in-progress merge"
+msgstr "bricht die sich im Gange befindliche Zusammenführung ab"
+
 #: builtin/merge.c:240
 msgid "could not run stash."
 msgstr "Konnte \"stash\" nicht ausführen."
@@ -3884,37 +5933,33 @@ msgstr "Ungültiger branch.%s.mergeoptions String: %s"
 msgid "git write-tree failed to write a tree"
 msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl"
 
-#: builtin/merge.c:678
-msgid "failed to read the cache"
-msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
-
-#: builtin/merge.c:709
+#: builtin/merge.c:656
 msgid "Not handling anything other than two heads merge."
 msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt."
 
-#: builtin/merge.c:723
+#: builtin/merge.c:670
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr "Unbekannte Option für merge-recursive: -X%s"
 
-#: builtin/merge.c:737
+#: builtin/merge.c:684
 #, c-format
 msgid "unable to write %s"
 msgstr "konnte %s nicht schreiben"
 
-#: builtin/merge.c:876
+#: builtin/merge.c:773
 #, c-format
 msgid "Could not read from '%s'"
 msgstr "konnte nicht von '%s' lesen"
 
-#: builtin/merge.c:885
+#: builtin/merge.c:782
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
 "Zusammenführung wurde nicht eingetragen; benutze 'git commit' um die "
 "Zusammenführung abzuschließen.\n"
 
-#: builtin/merge.c:891
+#: builtin/merge.c:788
 msgid ""
 "Please enter a commit message to explain why this merge is necessary,\n"
 "especially if it merges an updated upstream into a topic branch.\n"
@@ -3930,56 +5975,56 @@ msgstr ""
 "Zeilen beginnend mit '#' werden ignoriert, und eine leere Beschreibung "
 "bricht die Eintragung ab.\n"
 
-#: builtin/merge.c:915
+#: builtin/merge.c:812
 msgid "Empty commit message."
 msgstr "Leere Versionsbeschreibung"
 
-#: builtin/merge.c:927
+#: builtin/merge.c:824
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Wunderbar.\n"
 
-#: builtin/merge.c:992
+#: builtin/merge.c:889
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
 "Automatische Zusammenführung fehlgeschlagen; behebe die Konflikte und trage "
 "dann das Ergebnis ein.\n"
 
-#: builtin/merge.c:1008
+#: builtin/merge.c:905
 #, c-format
 msgid "'%s' is not a commit"
 msgstr "'%s' ist keine Version"
 
-#: builtin/merge.c:1049
+#: builtin/merge.c:946
 msgid "No current branch."
 msgstr "Du befindest dich auf keinem Zweig."
 
-#: builtin/merge.c:1051
+#: builtin/merge.c:948
 msgid "No remote for the current branch."
 msgstr "Kein externes Archiv für den aktuellen Zweig."
 
-#: builtin/merge.c:1053
+#: builtin/merge.c:950
 msgid "No default upstream defined for the current branch."
 msgstr ""
 "Es ist kein externes Standard-Projektarchiv für den aktuellen Zweig "
 "definiert."
 
-#: builtin/merge.c:1058
+#: builtin/merge.c:955
 #, c-format
 msgid "No remote tracking branch for %s from %s"
 msgstr "Kein externer Übernahmezweig für %s von %s"
 
-#: builtin/merge.c:1145 builtin/merge.c:1302
+#: builtin/merge.c:1042 builtin/merge.c:1199
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - nichts was wir zusammenführen können"
 
-#: builtin/merge.c:1213
+#: builtin/merge.c:1110
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "Es gibt keine Zusammenführung zum Abbrechen (vermisse MERGE_HEAD)"
 
-#: builtin/merge.c:1229 git-pull.sh:31
+#: builtin/merge.c:1126 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -3987,12 +6032,12 @@ msgstr ""
 "Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert).\n"
 "Bitte trage deine Änderungen ein, bevor du zusammenführen kannst."
 
-#: builtin/merge.c:1232 git-pull.sh:34
+#: builtin/merge.c:1129 git-pull.sh:34
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr ""
 "Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert)."
 
-#: builtin/merge.c:1236
+#: builtin/merge.c:1133
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -4000,86 +6045,186 @@ msgstr ""
 "Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n"
 "Bitte trage deine Änderungen ein, bevor du zusammenführen kannst."
 
-#: builtin/merge.c:1239
+#: builtin/merge.c:1136
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr ""
 "Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)."
 
-#: builtin/merge.c:1248
+#: builtin/merge.c:1145
 msgid "You cannot combine --squash with --no-ff."
 msgstr "Du kannst --squash nicht mit --no-ff kombinieren."
 
-#: builtin/merge.c:1253
+#: builtin/merge.c:1150
 msgid "You cannot combine --no-ff with --ff-only."
 msgstr "Du kannst --no-ff nicht mit --ff--only kombinieren."
 
-#: builtin/merge.c:1260
+#: builtin/merge.c:1157
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr "Keine Version angegeben und merge.defaultToUpstream ist nicht gesetzt."
 
-#: builtin/merge.c:1292
+#: builtin/merge.c:1189
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Kann nur exakt eine Version in einem leeren Zweig zusammenführen."
 
-#: builtin/merge.c:1295
+#: builtin/merge.c:1192
 msgid "Squash commit into empty head not supported yet"
 msgstr "Bin auf einem Zweig, der noch geboren wird; kann nicht quetschen."
 
-#: builtin/merge.c:1297
+#: builtin/merge.c:1194
 msgid "Non-fast-forward commit does not make sense into an empty head"
 msgstr "nicht vorzuspulende Version macht in einem leeren Zweig keinen Sinn"
 
-#: builtin/merge.c:1412
+#: builtin/merge.c:1309
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Aktualisiere %s..%s\n"
 
-#: builtin/merge.c:1450
+#: builtin/merge.c:1348
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Probiere wirklich triviale \"in-index\"-Zusammenführung...\n"
 
-#: builtin/merge.c:1457
+#: builtin/merge.c:1355
 #, c-format
 msgid "Nope.\n"
 msgstr "Nein.\n"
 
-#: builtin/merge.c:1489
+#: builtin/merge.c:1387
 msgid "Not possible to fast-forward, aborting."
 msgstr "Vorspulen nicht möglich, breche ab."
 
-#: builtin/merge.c:1512 builtin/merge.c:1591
+#: builtin/merge.c:1410 builtin/merge.c:1489
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Rücklauf des Zweiges bis zum Ursprung...\n"
 
-#: builtin/merge.c:1516
+#: builtin/merge.c:1414
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "Probiere Zusammenführungsstrategie %s...\n"
 
-#: builtin/merge.c:1582
+#: builtin/merge.c:1480
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "Keine Zusammenführungsstrategie behandelt diese Zusammenführung.\n"
 
-#: builtin/merge.c:1584
+#: builtin/merge.c:1482
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n"
 
-#: builtin/merge.c:1593
+#: builtin/merge.c:1491
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
 msgstr "Benutze \"%s\" um die Auflösung per Hand vorzubereiten.\n"
 
-#: builtin/merge.c:1605
+#: builtin/merge.c:1503
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Automatische Zusammenführung abgeschlossen; halte, wie gewünscht, vor der "
 "Eintragung an\n"
 
+#: builtin/merge-base.c:26
+msgid "git merge-base [-a|--all] <commit> <commit>..."
+msgstr "git merge-base [-a|--all] <Version> <Version>..."
+
+#: builtin/merge-base.c:27
+msgid "git merge-base [-a|--all] --octopus <commit>..."
+msgstr "git merge-base [-a|--all] --octopus <Version>..."
+
+#: builtin/merge-base.c:28
+msgid "git merge-base --independent <commit>..."
+msgstr "git merge-base --independent <Version>..."
+
+#: builtin/merge-base.c:29
+msgid "git merge-base --is-ancestor <commit> <commit>"
+msgstr "git merge-base --is-ancestor <Version> <Version>"
+
+#: builtin/merge-base.c:98
+msgid "output all common ancestors"
+msgstr "Ausgabe aller gemeinsamen Vorfahren"
+
+#: builtin/merge-base.c:99
+msgid "find ancestors for a single n-way merge"
+msgstr "findet Vorfahren für eine einzelne n-Wege-Zusammenführung"
+
+#: builtin/merge-base.c:100
+msgid "list revs not reachable from others"
+msgstr "listet Revisionen auf, die nicht durch Andere erreichbar sind"
+
+#: builtin/merge-base.c:102
+msgid "is the first one ancestor of the other?"
+msgstr "ist der Erste ein Vorfahre von dem Anderen?"
+
+#: builtin/merge-file.c:8
+msgid ""
+"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
+"file2"
+msgstr ""
+"git merge-file [Optionen] [-L Name1 [-L orig [-L Name2]]] Datei1 orig_Datei "
+"Datei2"
+
+#: builtin/merge-file.c:33
+msgid "send results to standard output"
+msgstr "sendet Ergebnisse zur Standard-Ausgabe"
+
+#: builtin/merge-file.c:34
+msgid "use a diff3 based merge"
+msgstr "benutzt eine diff3 basierte Zusammenführung"
+
+#: builtin/merge-file.c:35
+msgid "for conflicts, use our version"
+msgstr "verwendet bei Konflikten unsere Variante"
+
+#: builtin/merge-file.c:37
+msgid "for conflicts, use their version"
+msgstr "verwendet bei Konflikten ihre Variante"
+
+#: builtin/merge-file.c:39
+msgid "for conflicts, use a union version"
+msgstr "verwendet bei Konflikten eine gemeinsame Variante"
+
+#: builtin/merge-file.c:42
+msgid "for conflicts, use this marker size"
+msgstr "verwendet bei Konflikten diese Kennzeichnungslänge"
+
+#: builtin/merge-file.c:43
+msgid "do not warn about conflicts"
+msgstr "keine Warnung bei Konflikten"
+
+#: builtin/merge-file.c:45
+msgid "set labels for file1/orig_file/file2"
+msgstr "setzt Beschriftung für Datei1/orig_Datei/Datei2"
+
+#: builtin/mktree.c:67
+msgid "git mktree [-z] [--missing] [--batch]"
+msgstr "git mktree [-z] [--missing] [--batch]"
+
+#: builtin/mktree.c:153
+msgid "input is NUL terminated"
+msgstr "Eingabe ist durch NUL-Zeichen abgeschlossen"
+
+#: builtin/mktree.c:154 builtin/write-tree.c:24
+msgid "allow missing objects"
+msgstr "erlaubt fehlende Objekte"
+
+#: builtin/mktree.c:155
+msgid "allow creation of more than one tree"
+msgstr "erlaubt die Erstellung von mehr als einem Baum"
+
+#: builtin/mv.c:14
+msgid "git mv [options] <source>... <destination>"
+msgstr "git mv [Optionen] <Quelle>... <Ziel>"
+
+#: builtin/mv.c:64
+msgid "force move/rename even if target exists"
+msgstr "erzwingt Verschieben/Umbenennen, auch wenn das Ziel existiert"
+
+#: builtin/mv.c:65
+msgid "skip move/rename errors"
+msgstr "überspringt Fehler beim Verschieben oder Umbenennen"
+
 #: builtin/mv.c:108
 #, c-format
 msgid "Checking rename of '%s' to '%s'\n"
@@ -4142,115 +6287,288 @@ msgstr "Benenne %s nach %s um\n"
 msgid "renaming '%s' failed"
 msgstr "Umbenennung von '%s' fehlgeschlagen"
 
-#: builtin/notes.c:139
+#: builtin/name-rev.c:175
+msgid "git name-rev [options] <commit>..."
+msgstr "git name-rev [Optionen] <Version>..."
+
+#: builtin/name-rev.c:176
+msgid "git name-rev [options] --all"
+msgstr "git name-rev [Optionen] --all"
+
+#: builtin/name-rev.c:177
+msgid "git name-rev [options] --stdin"
+msgstr "git name-rev [Optionen] --stdin"
+
+#: builtin/name-rev.c:229
+msgid "print only names (no SHA-1)"
+msgstr "zeigt nur Namen an (keine SHA-1)"
+
+#: builtin/name-rev.c:230
+msgid "only use tags to name the commits"
+msgstr "benutzt nur Markierungen um die Versionen zu benennen"
+
+#: builtin/name-rev.c:232
+msgid "only use refs matching <pattern>"
+msgstr "benutzt nur Referenzen die <Muster> entsprechen"
+
+#: builtin/name-rev.c:234
+msgid "list all commits reachable from all refs"
+msgstr "listet alle Versionen auf, die von allen Referenzen erreichbar sind"
+
+#: builtin/name-rev.c:235
+msgid "read from stdin"
+msgstr "liest von der Standard-Eingabe"
+
+#: builtin/name-rev.c:236
+msgid "allow to print `undefined` names"
+msgstr "erlaubt Ausgabe von `undefinierten` Namen"
+
+#: builtin/notes.c:26
+msgid "git notes [--ref <notes_ref>] [list [<object>]]"
+msgstr "git notes [--ref <Notiz-Referenz>] [list [<Objekt>]]"
+
+#: builtin/notes.c:27
+msgid ""
+"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <Notiz-Referenz>] add [-f] [-m <Nachricht> | -F <Datei> | (-"
+"c | -C) <Objekt>] [<Objekt>]"
+
+#: builtin/notes.c:28
+msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
+msgstr ""
+"git notes [--ref <Notiz-Referenz>] copy [-f] <von-Objekt> <nach-Objekt>"
+
+#: builtin/notes.c:29
+msgid ""
+"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
+"<object>] [<object>]"
+msgstr ""
+"git notes [--ref <Notiz-Referenz>] append [-m <Nachricht> | -F <Datei> | (-c "
+"| -C) <Objekt>] [<Objekt>]"
+
+#: builtin/notes.c:30
+msgid "git notes [--ref <notes_ref>] edit [<object>]"
+msgstr "git notes [--ref <Notiz-Referenz>] edit [<Objekt>]"
+
+#: builtin/notes.c:31
+msgid "git notes [--ref <notes_ref>] show [<object>]"
+msgstr "git notes [--ref <Notiz-Referenz>] show [<Objekt>]"
+
+#: builtin/notes.c:32
+msgid ""
+"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
+msgstr ""
+"git notes [--ref <Notiz-Referenz>] merge [-v | -q] [-s <Strategie> ] <Notiz-"
+"Referenz>"
+
+#: builtin/notes.c:33
+msgid "git notes merge --commit [-v | -q]"
+msgstr "git notes merge --commit [-v | -q]"
+
+#: builtin/notes.c:34
+msgid "git notes merge --abort [-v | -q]"
+msgstr "git notes merge --abort [-v | -q]"
+
+#: builtin/notes.c:35
+msgid "git notes [--ref <notes_ref>] remove [<object>...]"
+msgstr "git notes [--ref <Notiz-Referenz>] remove [<Objekt>...]"
+
+#: builtin/notes.c:36
+msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
+msgstr "git notes [--ref <Notiz-Referenz>] prune [-n | -v]"
+
+#: builtin/notes.c:37
+msgid "git notes [--ref <notes_ref>] get-ref"
+msgstr "git notes [--ref <Notiz-Referenz>] get-ref"
+
+#: builtin/notes.c:42
+msgid "git notes [list [<object>]]"
+msgstr "git notes [list [<Objekt>]]"
+
+#: builtin/notes.c:47
+msgid "git notes add [<options>] [<object>]"
+msgstr "git notes add [<Optionen>] [<Objekt>]"
+
+#: builtin/notes.c:52
+msgid "git notes copy [<options>] <from-object> <to-object>"
+msgstr "git notes copy [<Optionen>] <von-Objekt> <nach-Objekt>"
+
+#: builtin/notes.c:53
+msgid "git notes copy --stdin [<from-object> <to-object>]..."
+msgstr "git notes copy --stdin [<von-Objekt> <nach-Objekt>]..."
+
+#: builtin/notes.c:58
+msgid "git notes append [<options>] [<object>]"
+msgstr "git notes append [<Optionen>] [<Objekt>]"
+
+#: builtin/notes.c:63
+msgid "git notes edit [<object>]"
+msgstr "git notes edit [<Objekt>]"
+
+#: builtin/notes.c:68
+msgid "git notes show [<object>]"
+msgstr "git notes show [<Objekt>]"
+
+#: builtin/notes.c:73
+msgid "git notes merge [<options>] <notes_ref>"
+msgstr "git notes merge [<Optionen>] <Notiz-Referenz>"
+
+#: builtin/notes.c:74
+msgid "git notes merge --commit [<options>]"
+msgstr "git notes merge --commit [<Optionen>]"
+
+#: builtin/notes.c:75
+msgid "git notes merge --abort [<options>]"
+msgstr "git notes merge --abort [<Optionen>]"
+
+#: builtin/notes.c:80
+msgid "git notes remove [<object>]"
+msgstr "git notes remove [<Objekt>]"
+
+#: builtin/notes.c:85
+msgid "git notes prune [<options>]"
+msgstr "git notes prune [<Optionen>]"
+
+#: builtin/notes.c:90
+msgid "git notes get-ref"
+msgstr "git notes get-ref"
+
+#: builtin/notes.c:142
 #, c-format
 msgid "unable to start 'show' for object '%s'"
 msgstr "konnte 'show' für Objekt '%s' nicht starten"
 
-#: builtin/notes.c:145
+#: builtin/notes.c:148
 msgid "can't fdopen 'show' output fd"
 msgstr "konnte Datei-Deskriptor für Ausgabe von 'show' nicht öffnen"
 
-#: builtin/notes.c:155
+#: builtin/notes.c:158
 #, c-format
 msgid "failed to close pipe to 'show' for object '%s'"
 msgstr "Schließen der Verbindung zu 'show' ist für Objekt '%s' fehlgeschlagen."
 
-#: builtin/notes.c:158
+#: builtin/notes.c:161
 #, c-format
 msgid "failed to finish 'show' for object '%s'"
 msgstr "konnte 'show' für Objekt '%s' nicht abschließen"
 
-#: builtin/notes.c:175 builtin/tag.c:347
+#: builtin/notes.c:178 builtin/tag.c:347
 #, c-format
 msgid "could not create file '%s'"
 msgstr "konnte Datei '%s' nicht erstellen"
 
-#: builtin/notes.c:189
+#: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
 msgstr "Bitte liefere den Notiz-Inhalt unter Verwendung der Option -m oder -F."
 
-#: builtin/notes.c:210 builtin/notes.c:973
+#: builtin/notes.c:213 builtin/notes.c:976
 #, c-format
 msgid "Removing note for object %s\n"
 msgstr "Entferne Notiz für Objekt %s\n"
 
-#: builtin/notes.c:215
+#: builtin/notes.c:218
 msgid "unable to write note object"
 msgstr "Konnte Notiz-Objekt nicht schreiben"
 
-#: builtin/notes.c:217
+#: builtin/notes.c:220
 #, c-format
 msgid "The note contents has been left in %s"
 msgstr "Die Notiz-Inhalte wurden in %s belassen"
 
-#: builtin/notes.c:251 builtin/tag.c:542
+#: builtin/notes.c:254 builtin/tag.c:542
 #, c-format
 msgid "cannot read '%s'"
 msgstr "kann '%s' nicht lesen"
 
-#: builtin/notes.c:253 builtin/tag.c:545
+#: builtin/notes.c:256 builtin/tag.c:545
 #, c-format
 msgid "could not open or read '%s'"
 msgstr "konnte '%s' nicht öffnen oder lesen"
 
-#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447
-#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644
-#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766
-#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558
+#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450
+#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647
+#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769
+#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
 msgstr "Konnte '%s' nicht als gültige Referenz auflösen."
 
-#: builtin/notes.c:275
+#: builtin/notes.c:278
 #, c-format
 msgid "Failed to read object '%s'."
 msgstr "Fehler beim Lesen des Objektes '%s'."
 
-#: builtin/notes.c:299
+#: builtin/notes.c:302
 msgid "Cannot commit uninitialized/unreferenced notes tree"
 msgstr "Kann uninitialisierten/unreferenzierten Notiz-Baum nicht eintragen."
 
-#: builtin/notes.c:340
+#: builtin/notes.c:343
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
 msgstr "Ungültiger notes.rewriteMode Wert: '%s'"
 
-#: builtin/notes.c:350
+#: builtin/notes.c:353
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
 msgstr ""
-"Neuschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)"
+"Umschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)"
 
 #. TRANSLATORS: The first %s is the name of the
 #. environment variable, the second %s is its value
-#: builtin/notes.c:377
+#: builtin/notes.c:380
 #, c-format
 msgid "Bad %s value: '%s'"
 msgstr "Ungültiger %s Wert: '%s'"
 
-#: builtin/notes.c:441
+#: builtin/notes.c:444
 #, c-format
 msgid "Malformed input line: '%s'."
 msgstr "Fehlerhafte Eingabezeile: '%s'."
 
-#: builtin/notes.c:456
+#: builtin/notes.c:459
 #, c-format
 msgid "Failed to copy notes from '%s' to '%s'"
 msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
 
-#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627
-#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759
-#: builtin/notes.c:1033
+#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630
+#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762
+#: builtin/notes.c:1036
 msgid "too many parameters"
 msgstr "zu viele Parameter"
 
-#: builtin/notes.c:513 builtin/notes.c:772
+#: builtin/notes.c:516 builtin/notes.c:775
 #, c-format
 msgid "No note found for object %s."
 msgstr "Kein Notiz für Objekt %s gefunden."
 
-#: builtin/notes.c:580
+#: builtin/notes.c:538 builtin/notes.c:695
+msgid "note contents as a string"
+msgstr "Notizinhalte als Zeichenkette"
+
+#: builtin/notes.c:541 builtin/notes.c:698
+msgid "note contents in a file"
+msgstr "Notizinhalte in einer Datei"
+
+#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700
+#: builtin/notes.c:703 builtin/tag.c:476
+msgid "object"
+msgstr "Objekt"
+
+#: builtin/notes.c:544 builtin/notes.c:701
+msgid "reuse and edit specified note object"
+msgstr "Wiederverwendung und Bearbeitung des angegebenen Notiz-Objektes"
+
+#: builtin/notes.c:547 builtin/notes.c:704
+msgid "reuse specified note object"
+msgstr "Wiederverwendung des angegebenen Notiz-Objektes"
+
+#: builtin/notes.c:549 builtin/notes.c:617
+msgid "replace existing notes"
+msgstr "ersetzt existierende Notizen"
+
+#: builtin/notes.c:583
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -4259,16 +6577,26 @@ msgstr ""
 "Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s "
 "gefunden. Verwende '-f' um die existierenden Notizen zu überschreiben."
 
-#: builtin/notes.c:585 builtin/notes.c:662
+#: builtin/notes.c:588 builtin/notes.c:665
 #, c-format
 msgid "Overwriting existing notes for object %s\n"
 msgstr "Überschreibe existierende Notizen für Objekt %s\n"
 
-#: builtin/notes.c:635
+#: builtin/notes.c:618
+msgid "read objects from stdin"
+msgstr "liest Objekte von der Standard-Eingabe"
+
+#: builtin/notes.c:620
+msgid "load rewriting config for <command> (implies --stdin)"
+msgstr ""
+"lädt Konfiguration für <Kommando> beim Umschreiben von Versionen (impliziert "
+"--stdin)"
+
+#: builtin/notes.c:638
 msgid "too few parameters"
 msgstr "zu wenig Parameter"
 
-#: builtin/notes.c:656
+#: builtin/notes.c:659
 #, c-format
 msgid ""
 "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -4277,12 +6605,12 @@ msgstr ""
 "Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. "
 "Verwende '-f' um die existierenden Notizen zu überschreiben."
 
-#: builtin/notes.c:668
+#: builtin/notes.c:671
 #, c-format
 msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Keine Notizen für Quell-Objekt %s. Kopie nicht möglich."
 
-#: builtin/notes.c:717
+#: builtin/notes.c:720
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -4291,41 +6619,264 @@ msgstr ""
 "Die Optionen -m/-F/-c/-C sind für das Unterkommando 'edit' veraltet.\n"
 "Bitte benutze stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
 
-#: builtin/notes.c:971
+#: builtin/notes.c:867
+msgid "General options"
+msgstr "Allgemeine Optionen"
+
+#: builtin/notes.c:869
+msgid "Merge options"
+msgstr "Optionen für Zusammenführung"
+
+#: builtin/notes.c:871
+msgid ""
+"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
+"cat_sort_uniq)"
+msgstr ""
+"löst Konflikte bei Notizen mit der angegebenen Strategie auf (manual/ours/"
+"theirs/union/cat_sort_uniq)"
+
+#: builtin/notes.c:873
+msgid "Committing unmerged notes"
+msgstr "trägt nicht zusammengeführte Notizen ein"
+
+#: builtin/notes.c:875
+msgid "finalize notes merge by committing unmerged notes"
+msgstr ""
+"schließt Zusammenführung von Notizen ab, in dem nicht zusammengeführte "
+"Notizen eingetragen werden"
+
+#: builtin/notes.c:877
+msgid "Aborting notes merge resolution"
+msgstr "bricht Konfliktauflösung bei Zusammenführung von Notizen ab"
+
+#: builtin/notes.c:879
+msgid "abort notes merge"
+msgstr "bricht Zusammenführung von Notizen ab"
+
+#: builtin/notes.c:974
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Objekt %s hat keine Notiz\n"
 
-#: builtin/notes.c:1103 builtin/remote.c:1598
+#: builtin/notes.c:986
+msgid "attempt to remove non-existent note is not an error"
+msgstr "der Versuch, eine nicht existierende Notiz zu löschen, ist kein Fehler"
+
+#: builtin/notes.c:989
+msgid "read object names from the standard input"
+msgstr "liest Objektnamen von der Standard-Eingabe"
+
+#: builtin/notes.c:1070
+msgid "notes_ref"
+msgstr "Notiz-Referenz"
+
+#: builtin/notes.c:1071
+msgid "use notes from <notes_ref>"
+msgstr "benutzt Notizen von <Notiz-Referenz>"
+
+#: builtin/notes.c:1106 builtin/remote.c:1598
 #, c-format
 msgid "Unknown subcommand: %s"
 msgstr "Unbekanntes Unterkommando: %s"
 
+#: builtin/pack-objects.c:23
+msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
+msgstr ""
+"git pack-objects --stdout [Optionen...] [< Referenzliste | < Objektliste]"
+
+#: builtin/pack-objects.c:24
+msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
+msgstr ""
+"git pack-objects [Optionen...] Basis-Name [< Referenzliste | < Objektliste]"
+
 #: builtin/pack-objects.c:183 builtin/pack-objects.c:186
 #, c-format
 msgid "deflate error (%d)"
 msgstr "Fehler beim Komprimieren (%d)"
 
-#: builtin/pack-objects.c:2398
+#: builtin/pack-objects.c:2397
 #, c-format
 msgid "unsupported index version %s"
 msgstr "Nicht unterstützte Bereitstellungsversion %s"
 
-#: builtin/pack-objects.c:2402
+#: builtin/pack-objects.c:2401
 #, c-format
 msgid "bad index version '%s'"
 msgstr "Ungültige Bereitstellungsversion '%s'"
 
-#: builtin/pack-objects.c:2425
+#: builtin/pack-objects.c:2424
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr "Option %s akzeptiert keine negative Form"
 
-#: builtin/pack-objects.c:2429
+#: builtin/pack-objects.c:2428
 #, c-format
 msgid "unable to parse value '%s' for option %s"
 msgstr "konnte Wert '%s' für Option %s nicht parsen"
 
+#: builtin/pack-objects.c:2447
+msgid "do not show progress meter"
+msgstr "zeigt keine Fortschrittsanzeige"
+
+#: builtin/pack-objects.c:2449
+msgid "show progress meter"
+msgstr "zeigt Fortschrittsanzeige"
+
+#: builtin/pack-objects.c:2451
+msgid "show progress meter during object writing phase"
+msgstr "zeigt Forschrittsanzeige während der Phase des Schreibens der Objekte"
+
+#: builtin/pack-objects.c:2454
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "ähnlich zu --all-progress wenn Fortschrittsanzeige darstellt wird"
+
+#: builtin/pack-objects.c:2455
+msgid "version[,offset]"
+msgstr "version[,offset]"
+
+#: builtin/pack-objects.c:2456
+msgid "write the pack index file in the specified idx format version"
+msgstr ""
+"schreibt die Index-Datei des Paketes in der angegebenen Indexformat-Version"
+
+#: builtin/pack-objects.c:2459
+msgid "maximum size of each output pack file"
+msgstr "maximale Größe für jede ausgegebene Paketdatei"
+
+#: builtin/pack-objects.c:2461
+msgid "ignore borrowed objects from alternate object store"
+msgstr "ignoriert geliehene Objekte von alternativem Objektspeicher"
+
+#: builtin/pack-objects.c:2463
+msgid "ignore packed objects"
+msgstr "ignoriert gepackte Objekte"
+
+#: builtin/pack-objects.c:2465
+msgid "limit pack window by objects"
+msgstr "begrenzt Paketfenster durch Objekte"
+
+#: builtin/pack-objects.c:2467
+msgid "limit pack window by memory in addition to object limit"
+msgstr "begrenzt Paketfenster, zusätzlich zur Objektbegrenzung, durch Speicher"
+
+#: builtin/pack-objects.c:2469
+msgid "maximum length of delta chain allowed in the resulting pack"
+msgstr ""
+"maximale Länge der erlaubten Differenzverkettung im resultierenden Paket"
+
+#: builtin/pack-objects.c:2471
+msgid "reuse existing deltas"
+msgstr "verwendet existierende Unterschiede wieder"
+
+#: builtin/pack-objects.c:2473
+msgid "reuse existing objects"
+msgstr "verwendet existierende Objekte wieder"
+
+#: builtin/pack-objects.c:2475
+msgid "use OFS_DELTA objects"
+msgstr "benutzt OFS_DELTA Objekte"
+
+#: builtin/pack-objects.c:2477
+msgid "use threads when searching for best delta matches"
+msgstr ""
+"benutzt Threads bei der Suche nach den besten Übereinstimmungen bei "
+"Unterschieden"
+
+#: builtin/pack-objects.c:2479
+msgid "do not create an empty pack output"
+msgstr "erzeugt keine leeren Pakete"
+
+#: builtin/pack-objects.c:2481
+msgid "read revision arguments from standard input"
+msgstr "liest Argumente bezüglich Revisionen von der Standard-Eingabe"
+
+#: builtin/pack-objects.c:2483
+msgid "limit the objects to those that are not yet packed"
+msgstr "begrenzt die Objekte zu solchen, die noch nicht gepackt wurden"
+
+#: builtin/pack-objects.c:2486
+msgid "include objects reachable from any reference"
+msgstr "schließt Objekte ein, die von jeder Referenz erreichbar sind"
+
+#: builtin/pack-objects.c:2489
+msgid "include objects referred by reflog entries"
+msgstr ""
+"schließt Objekte ein, die von Einträgen des Referenzprotokolls referenziert "
+"werden"
+
+#: builtin/pack-objects.c:2492
+msgid "output pack to stdout"
+msgstr "schreibt Paket in die Standard-Ausgabe"
+
+#: builtin/pack-objects.c:2494
+msgid "include tag objects that refer to objects to be packed"
+msgstr ""
+"schließt Markierungsobjekte ein, die auf gepackte Objekte referenzieren"
+
+#: builtin/pack-objects.c:2496
+msgid "keep unreachable objects"
+msgstr "behält nicht erreichbare Objekte"
+
+#: builtin/pack-objects.c:2497 parse-options.h:141
+msgid "time"
+msgstr "Zeit"
+
+#: builtin/pack-objects.c:2498
+msgid "unpack unreachable objects newer than <time>"
+msgstr "entpackt nicht erreichbare Objekte, die neuer als <Zeit> sind"
+
+#: builtin/pack-objects.c:2501
+msgid "create thin packs"
+msgstr "erzeugt dünnere Pakete"
+
+#: builtin/pack-objects.c:2503
+msgid "ignore packs that have companion .keep file"
+msgstr "ignoriert Pakete die .keep Dateien haben"
+
+#: builtin/pack-objects.c:2505
+msgid "pack compression level"
+msgstr "Komprimierungsgrad für Paketierung"
+
+#: builtin/pack-objects.c:2507
+msgid "do not hide commits by grafts"
+msgstr "verbirgt keine Versionen mit künstlichen Vorgängern (\"grafts\")"
+
+#: builtin/pack-refs.c:6
+msgid "git pack-refs [options]"
+msgstr "git pack-refs [Optionen]"
+
+#: builtin/pack-refs.c:14
+msgid "pack everything"
+msgstr "packt alles"
+
+#: builtin/pack-refs.c:15
+msgid "prune loose refs (default)"
+msgstr "entfernt lose Referenzen (Standard)"
+
+#: builtin/prune-packed.c:7
+msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
+msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]"
+
+#: builtin/prune.c:12
+msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
+msgstr "git prune [-n] [-v] [--expire <Zeit>] [--] [<Zweigspitze>...]"
+
+#: builtin/prune.c:132
+msgid "do not remove, show only"
+msgstr "nicht löschen, nur anzeigen"
+
+#: builtin/prune.c:133
+msgid "report pruned objects"
+msgstr "meldet gelöschte Objekte"
+
+#: builtin/prune.c:136
+msgid "expire objects older than <time>"
+msgstr "lässt Objekte älter als <Zeit> verfallen"
+
+#: builtin/push.c:14
+msgid "git push [<options>] [<repository> [<refspec>...]]"
+msgstr "git push [<Optionen>] [<Projektarchiv> [<Referenzspezifikation>...]]"
+
 #: builtin/push.c:45
 msgid "tag shorthand without <tag>"
 msgstr "Kurzschrift für Markierung ohne <Markierung>"
@@ -4434,20 +6985,20 @@ msgstr ""
 "'push.default' ist nicht gesetzt; der implizit gesetzte Wert\n"
 "wird in Git 2.0 von 'matching' nach 'simple' geändert. Um diese Meldung zu\n"
 "unterdrücken und das aktuelle Verhalten nach Änderung des Standardwertes\n"
-"beizubehalten, benutze:"
-"\n"
+"beizubehalten, benutze:\n"
 "  git config --global push.default matching\n"
 "\n"
-"Um diese Meldung zu unterdrücken und das neue Verhalten jetzt zu übernehmen,\n"
+"Um diese Meldung zu unterdrücken und das neue Verhalten jetzt zu "
+"übernehmen,\n"
 "benutze:\n"
 "\n"
 "  git config --global push.default simple\n"
 "\n"
 "Führe 'git help config' aus und suche nach 'push.default' für weitere "
 "Informationen.\n"
-"(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutze den ähnlichen"
-" Modus 'current' anstatt 'simple', falls du gelegentlich ältere Versionen von"
-" Git benutzt.)"
+"(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutze den ähnlichen "
+"Modus 'current' anstatt 'simple', falls du gelegentlich ältere Versionen von "
+"Git benutzt.)"
 
 #: builtin/push.c:199
 msgid ""
@@ -4555,6 +7106,55 @@ msgstr "--mirror kann nicht mit Referenzspezifikationen kombiniert werden"
 msgid "--all and --mirror are incompatible"
 msgstr "--all und --mirror sind inkompatibel"
 
+#: builtin/push.c:382
+msgid "repository"
+msgstr "Projektarchiv"
+
+#: builtin/push.c:383
+msgid "push all refs"
+msgstr "versendet alle Referenzen"
+
+#: builtin/push.c:384
+msgid "mirror all refs"
+msgstr "spiegelt alle Referenzen"
+
+#: builtin/push.c:386
+msgid "delete refs"
+msgstr "löscht Referenzen"
+
+#: builtin/push.c:387
+msgid "push tags (can't be used with --all or --mirror)"
+msgstr ""
+"versendet Markierungen (kann nicht mit --all oder --mirror benutzt werden)"
+
+#: builtin/push.c:390
+msgid "force updates"
+msgstr "erzwingt Aktualisierung"
+
+#: builtin/push.c:391
+msgid "check"
+msgstr ""
+
+#: builtin/push.c:392
+msgid "control recursive pushing of submodules"
+msgstr "steuert rekursives Versenden von Unterprojekten"
+
+#: builtin/push.c:394
+msgid "use thin pack"
+msgstr "benutzt kleinere Pakete"
+
+#: builtin/push.c:395 builtin/push.c:396
+msgid "receive pack program"
+msgstr "'receive pack' Programm"
+
+#: builtin/push.c:397
+msgid "set upstream for git pull/status"
+msgstr "setzt externes Projektarchiv für \"git pull/status\""
+
+#: builtin/push.c:400
+msgid "prune locally removed refs"
+msgstr "entfernt lokal gelöschte Referenzen"
+
 #: builtin/push.c:410
 msgid "--delete is incompatible with --all, --mirror and --tags"
 msgstr "--delete ist inkompatibel mit --all, --mirror und --tags"
@@ -4563,6 +7163,163 @@ msgstr "--delete ist inkompatibel mit --all, --mirror und --tags"
 msgid "--delete doesn't make sense without any refs"
 msgstr "--delete macht ohne irgendeine Referenz keinen Sinn"
 
+#: builtin/read-tree.c:36
+msgid ""
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] "
+"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
+"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
+msgstr ""
+"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<Prefix>] "
+"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
+"index-output=<Datei>] (--empty | <Versionsreferenz1> [<Versionsreferenz2> "
+"[<Versionsreferenz3>]])"
+
+#: builtin/read-tree.c:108
+msgid "write resulting index to <file>"
+msgstr "schreibt resultierende Bereitstellung nach <Datei>"
+
+#: builtin/read-tree.c:111
+msgid "only empty the index"
+msgstr "leert die Bereitstellung"
+
+#: builtin/read-tree.c:113
+msgid "Merging"
+msgstr "Zusammenführung"
+
+#: builtin/read-tree.c:115
+msgid "perform a merge in addition to a read"
+msgstr "führt eine Zusammenführung zusätzlich zum Lesen aus"
+
+#: builtin/read-tree.c:117
+msgid "3-way merge if no file level merging required"
+msgstr ""
+"3-Wege-Zusammenführung, wenn keine Zusammenführung auf Dateiebene "
+"erforderlich ist"
+
+#: builtin/read-tree.c:119
+msgid "3-way merge in presence of adds and removes"
+msgstr ""
+"3-Wege-Zusammenführung bei Vorhandensein von hinzugefügten/entfernten Zeilen"
+
+#: builtin/read-tree.c:121
+msgid "same as -m, but discard unmerged entries"
+msgstr "genau wie -m, verwirft aber nicht zusammengeführte Einträge"
+
+#: builtin/read-tree.c:122
+msgid "<subdirectory>/"
+msgstr "<Unterverzeichnis>/"
+
+#: builtin/read-tree.c:123
+msgid "read the tree into the index under <subdirectory>/"
+msgstr "liest den Baum in die Bereitstellung unter <Unterverzeichnis>/"
+
+#: builtin/read-tree.c:126
+msgid "update working tree with merge result"
+msgstr "aktualisiert Arbeitsbaum mit Ergebnis der Zusammenführung"
+
+#: builtin/read-tree.c:128
+msgid "gitignore"
+msgstr "gitignore"
+
+#: builtin/read-tree.c:129
+msgid "allow explicitly ignored files to be overwritten"
+msgstr "erlaubt explizit ignorierte Dateien zu überschreiben"
+
+#: builtin/read-tree.c:132
+msgid "don't check the working tree after merging"
+msgstr "prüft nicht den Arbeitsbaum nach der Zusammenführung"
+
+#: builtin/read-tree.c:133
+msgid "don't update the index or the work tree"
+msgstr "aktualisiert weder die Bereitstellung, noch den Arbeitsbaum"
+
+#: builtin/read-tree.c:135
+msgid "skip applying sparse checkout filter"
+msgstr "überspringt Anwendung des Filters für spärliches Auschecken"
+
+#: builtin/read-tree.c:137
+msgid "debug unpack-trees"
+msgstr "protokolliert Entpacken der Bäume"
+
+#: builtin/remote.c:11
+msgid "git remote [-v | --verbose]"
+msgstr "git remote [-v | --verbose]"
+
+#: builtin/remote.c:12
+msgid ""
+"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <name> <url>"
+msgstr ""
+"git remote add [-t <Zweig>] [-m <master>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <Name> <URL>"
+
+#: builtin/remote.c:13 builtin/remote.c:32
+msgid "git remote rename <old> <new>"
+msgstr "git remote rename <alt> <neu>"
+
+#: builtin/remote.c:14 builtin/remote.c:37
+msgid "git remote remove <name>"
+msgstr "git remote remove <Name>"
+
+#: builtin/remote.c:15 builtin/remote.c:42
+msgid "git remote set-head <name> (-a | -d | <branch>)"
+msgstr "git remote set-head <Name> (-a | -d | <Zweig>)"
+
+#: builtin/remote.c:16
+msgid "git remote [-v | --verbose] show [-n] <name>"
+msgstr "git remote [-v | --verbose] show [-n] <Name>"
+
+#: builtin/remote.c:17
+msgid "git remote prune [-n | --dry-run] <name>"
+msgstr "git remote prune [-n | --dry-run] <Name>"
+
+#: builtin/remote.c:18
+msgid ""
+"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
+msgstr ""
+"git remote [-v | --verbose] update [-p | --prune] [(<Gruppe> | "
+"<externesProjektarchiv>)...]"
+
+#: builtin/remote.c:19
+msgid "git remote set-branches [--add] <name> <branch>..."
+msgstr "git remote set-branches [--add] <Name> <Zweig>..."
+
+#: builtin/remote.c:20 builtin/remote.c:68
+msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
+msgstr "git remote set-url [--push] <Name> <neueURL> [<alteURL>]"
+
+#: builtin/remote.c:21 builtin/remote.c:69
+msgid "git remote set-url --add <name> <newurl>"
+msgstr "git remote set-url --add <Name> <neueURL>"
+
+#: builtin/remote.c:22 builtin/remote.c:70
+msgid "git remote set-url --delete <name> <url>"
+msgstr "git remote set-url --delete <Name> <URL>"
+
+#: builtin/remote.c:27
+msgid "git remote add [<options>] <name> <url>"
+msgstr "git remote add [<Optionen>] <Name> <URL>"
+
+#: builtin/remote.c:47
+msgid "git remote set-branches <name> <branch>..."
+msgstr "git remote set-branches <Name> <Zweig>..."
+
+#: builtin/remote.c:48
+msgid "git remote set-branches --add <name> <branch>..."
+msgstr "git remote set-branches --add <Name> <Zweig>..."
+
+#: builtin/remote.c:53
+msgid "git remote show [<options>] <name>"
+msgstr "git remote show [<Optionen>] <Name>"
+
+#: builtin/remote.c:58
+msgid "git remote prune [<options>] <name>"
+msgstr "git remote prune [<Optionen>] <Name>"
+
+#: builtin/remote.c:63
+msgid "git remote update [<options>] [<group> | <remote>]..."
+msgstr "git remote update [<Optionen>] [<Gruppe> | <externesProjektarchiv>]..."
+
 #: builtin/remote.c:98
 #, c-format
 msgid "Updating %s"
@@ -4576,10 +7333,39 @@ msgstr ""
 "--mirror ist gefährlich und veraltet; bitte\n"
 "\t benutze stattdessen --mirror=fetch oder --mirror=push"
 
-#: builtin/remote.c:147
-#, c-format
-msgid "unknown mirror argument: %s"
-msgstr "unbekanntes Argument für Option --mirror: %s"
+#: builtin/remote.c:147
+#, c-format
+msgid "unknown mirror argument: %s"
+msgstr "unbekanntes Argument für Option --mirror: %s"
+
+#: builtin/remote.c:163
+msgid "fetch the remote branches"
+msgstr "fordert die externen Zweige an"
+
+#: builtin/remote.c:165
+msgid "import all tags and associated objects when fetching"
+msgstr "importiert alle Markierungen und verbundene Objekte beim Anfordern"
+
+#: builtin/remote.c:168
+msgid "or do not fetch any tag at all (--no-tags)"
+msgstr "oder fordere gar keine Zweige an (--no-tags)"
+
+#: builtin/remote.c:170
+msgid "branch(es) to track"
+msgstr "Zweige zur Übernahme"
+
+#: builtin/remote.c:171
+msgid "master branch"
+msgstr "Hauptzweig"
+
+#: builtin/remote.c:172
+msgid "push|fetch"
+msgstr "push|fetch"
+
+#: builtin/remote.c:173
+msgid "set up remote as a mirror to push to or fetch from"
+msgstr ""
+"Aufsetzen des Fernarchivs als Spiegelarchiv zum Versenden und Anfordern"
 
 #: builtin/remote.c:185
 msgid "specifying a master branch makes no sense with --mirror"
@@ -4588,7 +7374,7 @@ msgstr "Angabe eines Hauptzweiges macht mit --mirror keinen Sinn"
 #: builtin/remote.c:187
 msgid "specifying branches to track makes sense only with fetch mirrors"
 msgstr ""
-"die Angabe von zu folgenden Zweigen macht nur mit dem Abholen von "
+"die Angabe von zu folgenden Zweigen macht nur mit dem Anfordern von "
 "Spiegelarchiven Sinn"
 
 #: builtin/remote.c:195 builtin/remote.c:646
@@ -4679,7 +7465,7 @@ msgstr "Konnte '%s' nicht erstellen"
 #: builtin/remote.c:764
 #, c-format
 msgid "Could not remove branch %s"
-msgstr "Konnte Zweig %s nicht entfernen"
+msgstr "Konnte Zweig %s nicht löschen"
 
 #: builtin/remote.c:834
 msgid ""
@@ -4690,8 +7476,8 @@ msgid_plural ""
 "to delete them, use:"
 msgstr[0] ""
 "Hinweis: Ein Zweig außerhalb der /refs/remotes/ Hierachie wurde nicht "
-"entfernt;\n"
-"um diesen zu entfernen, benutze:"
+"gelöscht;\n"
+"um diesen zu löschen, benutze:"
 msgstr[1] ""
 "Hinweis: Einige Zweige außer der /refs/remotes/ Hierarchie wurden nicht "
 "entfernt;\n"
@@ -4708,7 +7494,7 @@ msgstr " gefolgt"
 
 #: builtin/remote.c:948
 msgid " stale (use 'git remote prune' to remove)"
-msgstr " veraltet (benutze 'git remote prune' zum Entfernen)"
+msgstr " veraltet (benutze 'git remote prune' zum Löschen)"
 
 #: builtin/remote.c:950
 msgid " ???"
@@ -4782,6 +7568,10 @@ msgstr "    %-*s erzwingt Versand nach %s"
 msgid "    %-*s pushes to %s"
 msgstr "    %-*s versendet nach %s"
 
+#: builtin/remote.c:1091
+msgid "do not query remotes"
+msgstr "keine Abfrage von Fernarchiven"
+
 #: builtin/remote.c:1118
 #, c-format
 msgid "* remote %s"
@@ -4842,6 +7632,14 @@ msgid_plural "  Local refs configured for 'git push'%s:"
 msgstr[0] "  Lokale Referenz konfiguriert für 'git push'%s:"
 msgstr[1] "  Lokale Referenzen konfiguriert für 'git push'%s:"
 
+#: builtin/remote.c:1199
+msgid "set refs/remotes/<name>/HEAD according to remote"
+msgstr "setzt refs/remotes/<Name>/HEAD gemäß dem Fernarchiv"
+
+#: builtin/remote.c:1201
+msgid "delete refs/remotes/<name>/HEAD"
+msgstr "entfernt refs/remotes/<Name>/HEAD"
+
 #: builtin/remote.c:1216
 msgid "Cannot determine remote HEAD"
 msgstr "Kann Hauptzweig des externen Projektarchivs nicht bestimmen"
@@ -4897,15 +7695,35 @@ msgstr " * [würde veralteten Zweig entfernen] %s"
 msgid " * [pruned] %s"
 msgstr "* [veralteten Zweig entfernt] %s"
 
+#: builtin/remote.c:1321
+msgid "prune remotes after fetching"
+msgstr "entfernt veraltete Zweige im Fernarchiv nach dem Abholen"
+
 #: builtin/remote.c:1387 builtin/remote.c:1461
 #, c-format
 msgid "No such remote '%s'"
 msgstr "Kein solches externes Projektarchiv '%s'"
 
+#: builtin/remote.c:1407
+msgid "add branch"
+msgstr "fügt Zweig hinzu"
+
 #: builtin/remote.c:1414
 msgid "no remote specified"
 msgstr "kein externes Projektarchiv angegeben"
 
+#: builtin/remote.c:1436
+msgid "manipulate push URLs"
+msgstr "manipuliert URLs zum Versenden"
+
+#: builtin/remote.c:1438
+msgid "add URL"
+msgstr "fügt URL hinzu"
+
+#: builtin/remote.c:1440
+msgid "delete URLs"
+msgstr "löscht URLs"
+
 #: builtin/remote.c:1447
 msgid "--add --delete doesn't make sense"
 msgstr "--add --delete macht keinen Sinn"
@@ -4924,6 +7742,56 @@ msgstr "Keine solche URL gefunden: %s"
 msgid "Will not delete all non-push URLs"
 msgstr "Werde keine URLs entfernen, die nicht für den Versand bestimmt sind"
 
+#: builtin/remote.c:1569
+msgid "be verbose; must be placed before a subcommand"
+msgstr "erweiterte Ausgaben; muss vor einem Unterkommando angegeben werden"
+
+#: builtin/replace.c:17
+msgid "git replace [-f] <object> <replacement>"
+msgstr "git replace [-f] <Objekt> <Ersetzung>"
+
+#: builtin/replace.c:18
+msgid "git replace -d <object>..."
+msgstr "git replace -d <Objekt>..."
+
+#: builtin/replace.c:19
+msgid "git replace -l [<pattern>]"
+msgstr "git replace -l [<Muster>]"
+
+#: builtin/replace.c:121
+msgid "list replace refs"
+msgstr "listet ersetzende Referenzen auf"
+
+#: builtin/replace.c:122
+msgid "delete replace refs"
+msgstr "löscht ersetzende Referenzen"
+
+#: builtin/replace.c:123
+msgid "replace the ref if it exists"
+msgstr "ersetzt die Referenz, wenn sie existiert"
+
+#: builtin/rerere.c:11
+msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
+msgstr "git rerere [clean | forget path... | status | remaining | diff | gc]"
+
+#: builtin/rerere.c:56
+msgid "register clean resolutions in index"
+msgstr "registriert saubere Auflösungen in der Bereitstellung"
+
+#: builtin/reset.c:25
+msgid ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
+msgstr ""
+"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<Version>]"
+
+#: builtin/reset.c:26
+msgid "git reset [-q] <commit> [--] <paths>..."
+msgstr "git reset [-q] <Version> [--] <Pfade>..."
+
+#: builtin/reset.c:27
+msgid "git reset --patch [<commit>] [--] [<paths>...]"
+msgstr "git reset --patch [<Version>] [--] [<Pfade>...]"
+
 #: builtin/reset.c:33
 msgid "mixed"
 msgstr "mixed"
@@ -4981,6 +7849,26 @@ msgstr ""
 "Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im "
 "Gange ist."
 
+#: builtin/reset.c:238
+msgid "be quiet, only report errors"
+msgstr "weniger Ausgaben, meldet nur Fehler"
+
+#: builtin/reset.c:240
+msgid "reset HEAD and index"
+msgstr "setzt Zweigspitze (HEAD) und Bereitstellung zurück"
+
+#: builtin/reset.c:241
+msgid "reset only HEAD"
+msgstr "setzt nur Zweigspitze (HEAD) zurück"
+
+#: builtin/reset.c:243 builtin/reset.c:245
+msgid "reset HEAD, index and working tree"
+msgstr "setzt Zweigspitze (HEAD), Bereitstellung und Arbeitsbaum zurück"
+
+#: builtin/reset.c:247
+msgid "reset HEAD but keep local changes"
+msgstr "setzt Zweigspitze (HEAD) zurück, behält aber lokale Änderungen"
+
 #: builtin/reset.c:303
 #, c-format
 msgid "Could not parse object '%s'."
@@ -5010,24 +7898,137 @@ msgstr "'%s' Zurücksetzung ist in einem bloßen Projektarchiv nicht erlaubt"
 msgid "Could not reset index file to revision '%s'."
 msgstr "Konnte Bereitstellungsdatei nicht zu Version '%s' zurücksetzen."
 
+#: builtin/rev-parse.c:339
+msgid "git rev-parse --parseopt [options] -- [<args>...]"
+msgstr "git rev-parse --parseopt [Optionen] -- [<Argumente>...]"
+
+#: builtin/rev-parse.c:344
+msgid "keep the `--` passed as an arg"
+msgstr "lässt `--` als Argument"
+
+#: builtin/rev-parse.c:346
+msgid "stop parsing after the first non-option argument"
+msgstr "stoppt das Parsen nach dem ersten Argument was keine Option ist"
+
+#: builtin/rev-parse.c:464
+msgid ""
+"git rev-parse --parseopt [options] -- [<args>...]\n"
+"   or: git rev-parse --sq-quote [<arg>...]\n"
+"   or: git rev-parse [options] [<arg>...]\n"
+"\n"
+"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
+msgstr ""
+"git rev-parse --parseopt [Optionen] -- [<Argumente>...]\n"
+"   oder: git rev-parse --sq-quote [<Argumente>...]\n"
+"   oder: git rev-parse [Optionen] [<Argumente>...]\n"
+"\n"
+"Führe \"git rev-parse --parseopt -h\" für weitere Informationen bei erster "
+"Verwendung aus."
+
+#: builtin/revert.c:22
+msgid "git revert [options] <commit-ish>"
+msgstr "git revert [options] <Versionsangabe>"
+
+#: builtin/revert.c:23
+msgid "git revert <subcommand>"
+msgstr "git revert <Unterkommando>"
+
+#: builtin/revert.c:28
+msgid "git cherry-pick [options] <commit-ish>"
+msgstr "git cherry-pick [Optionen] <Versionsangabe>"
+
+#: builtin/revert.c:29
+msgid "git cherry-pick <subcommand>"
+msgstr "git cherry-pick <Unterkommando>"
+
 #: builtin/revert.c:70 builtin/revert.c:92
 #, c-format
 msgid "%s: %s cannot be used with %s"
 msgstr "%s: %s kann nicht mit %s benutzt werden"
 
-#: builtin/revert.c:131
+#: builtin/revert.c:103
+msgid "end revert or cherry-pick sequence"
+msgstr "beendet \"revert\" oder \"cherry-pick\" Ablauf"
+
+#: builtin/revert.c:104
+msgid "resume revert or cherry-pick sequence"
+msgstr "setzt \"revert\" oder \"cherry-pick\" Ablauf fort"
+
+#: builtin/revert.c:105
+msgid "cancel revert or cherry-pick sequence"
+msgstr "bricht \"revert\" oder \"cherry-pick\" Ablauf ab"
+
+#: builtin/revert.c:106
+msgid "don't automatically commit"
+msgstr "trägt nicht automatisch ein"
+
+#: builtin/revert.c:107
+msgid "edit the commit message"
+msgstr "Bearbeitung der Versionsbeschreibung"
+
+#: builtin/revert.c:110
+msgid "parent number"
+msgstr "Nummer des Elternteils"
+
+#: builtin/revert.c:112
+msgid "merge strategy"
+msgstr "Zusammenführungsstrategie"
+
+#: builtin/revert.c:113
+msgid "option"
+msgstr "Option"
+
+#: builtin/revert.c:114
+msgid "option for merge strategy"
+msgstr "Option für Zusammenführungsstrategie"
+
+#: builtin/revert.c:125
+msgid "append commit name"
+msgstr "hängt Versionsnamen an"
+
+#: builtin/revert.c:126
+msgid "allow fast-forward"
+msgstr "erlaubt Vorspulen"
+
+#: builtin/revert.c:127
+msgid "preserve initially empty commits"
+msgstr "erhält ursprüngliche, leere Versionen"
+
+#: builtin/revert.c:128
+msgid "allow commits with empty messages"
+msgstr "erlaubt Version mit leerer Beschreibung"
+
+#: builtin/revert.c:129
+msgid "keep redundant, empty commits"
+msgstr "behält redundante, leere Versionen"
+
+#: builtin/revert.c:133
 msgid "program error"
 msgstr "Programmfehler"
 
-#: builtin/revert.c:221
+#: builtin/revert.c:223
 msgid "revert failed"
 msgstr "\"revert\" fehlgeschlagen"
 
-#: builtin/revert.c:236
+#: builtin/revert.c:238
 msgid "cherry-pick failed"
 msgstr "\"cherry-pick\" fehlgeschlagen"
 
-#: builtin/rm.c:109
+#: builtin/rm.c:15
+msgid "git rm [options] [--] <file>..."
+msgstr "git rm [Optionen] [--] [<Datei>...]"
+
+#: builtin/rm.c:64 builtin/rm.c:186
+#, c-format
+msgid ""
+"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+"Unterprojekt '%s' (oder ein geschachteltes Unterprojekt hiervon) verwendet\n"
+"ein .git-Verzeichnis (benutze 'rm -rf' wenn du dieses wirklich mitsamt\n"
+"seiner Historie löschen möchtest)"
+
+#: builtin/rm.c:174
 #, c-format
 msgid ""
 "'%s' has staged content different from both the file and the HEAD\n"
@@ -5036,7 +8037,7 @@ msgstr ""
 "'%s' hat bereitgestellten Inhalt unterschiedlich zu der Datei und der\n"
 "Zweigspitze (HEAD) (benutze -f um die Entfernung zu erzwingen)"
 
-#: builtin/rm.c:115
+#: builtin/rm.c:180
 #, c-format
 msgid ""
 "'%s' has changes staged in the index\n"
@@ -5046,7 +8047,7 @@ msgstr ""
 "(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu "
 "erzwingen)"
 
-#: builtin/rm.c:119
+#: builtin/rm.c:191
 #, c-format
 msgid ""
 "'%s' has local modifications\n"
@@ -5056,21 +8057,248 @@ msgstr ""
 "(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu "
 "erzwingen)"
 
-#: builtin/rm.c:194
+#: builtin/rm.c:207
+msgid "do not list removed files"
+msgstr "listet keine gelöschten Dateien auf"
+
+#: builtin/rm.c:208
+msgid "only remove from the index"
+msgstr "entfernt nur aus der Bereitstellung"
+
+#: builtin/rm.c:209
+msgid "override the up-to-date check"
+msgstr "überschreibt die \"up-to-date\" Prüfung"
+
+#: builtin/rm.c:210
+msgid "allow recursive removal"
+msgstr "erlaubt rekursive Entfernung"
+
+#: builtin/rm.c:212
+msgid "exit with a zero status even if nothing matched"
+msgstr "beendet mit Rückgabewert 0, wenn keine Übereinstimmung gefunden wurde"
+
+#: builtin/rm.c:283
 #, c-format
 msgid "not removing '%s' recursively without -r"
 msgstr "'%s' wird nicht ohne -r rekursiv entfernt"
 
-#: builtin/rm.c:230
+#: builtin/rm.c:322
 #, c-format
 msgid "git rm: unable to remove %s"
-msgstr "git rm: konnte %s nicht entfernen"
+msgstr "git rm: konnte %s nicht löschen"
+
+#: builtin/shortlog.c:13
+msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"
+msgstr ""
+"git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] "
+"[<Versionsidentifikation>... ]"
 
 #: builtin/shortlog.c:157
 #, c-format
 msgid "Missing author: %s"
 msgstr "fehlender Autor: %s"
 
+#: builtin/shortlog.c:253
+msgid "sort output according to the number of commits per author"
+msgstr "sortiert die Ausgabe entsprechend der Anzahl von Versionen pro Autor"
+
+#: builtin/shortlog.c:255
+msgid "Suppress commit descriptions, only provides commit count"
+msgstr "Unterdrückt Versionsbeschreibungen, liefert nur Anzahl der Versionen"
+
+#: builtin/shortlog.c:257
+msgid "Show the email address of each author"
+msgstr "Zeigt die Email-Adresse von jedem Autor"
+
+#: builtin/shortlog.c:258
+msgid "w[,i1[,i2]]"
+msgstr "w[,i1[,i2]]"
+
+#: builtin/shortlog.c:259
+msgid "Linewrap output"
+msgstr "Ausgabe mit Zeilenumbrüchen"
+
+#: builtin/show-branch.c:9
+msgid ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
+"<glob>)...]"
+msgstr ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<Wann>] | --no-color] [--sparse] [--more=<n> | --list | --"
+"independent | --merge-base] [--no-name | --sha1-name] [--topics] "
+"[(<Revision> | <glob>)...]"
+
+#: builtin/show-branch.c:10
+msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
+msgstr "git show-branch (-g|--reflog)[=<n>[,<Basis>]] [--list] [<Referenz>]"
+
+#: builtin/show-branch.c:651
+msgid "show remote-tracking and local branches"
+msgstr "zeigt externe Übernahmezweige und lokale Zweige an"
+
+#: builtin/show-branch.c:653
+msgid "show remote-tracking branches"
+msgstr "zeigt externe Übernahmezweige an"
+
+#: builtin/show-branch.c:655
+msgid "color '*!+-' corresponding to the branch"
+msgstr "färbt '*!+-' entsprechend des Zweiges ein"
+
+#: builtin/show-branch.c:657
+msgid "show <n> more commits after the common ancestor"
+msgstr "zeigt <n> weitere Versionen nach dem gemeinsamen Vorfahren"
+
+#: builtin/show-branch.c:659
+msgid "synonym to more=-1"
+msgstr "Synonym für more=-1"
+
+#: builtin/show-branch.c:660
+msgid "suppress naming strings"
+msgstr "unterdrückt Namen"
+
+#: builtin/show-branch.c:662
+msgid "include the current branch"
+msgstr "bezieht den aktuellen Zweig ein"
+
+#: builtin/show-branch.c:664
+msgid "name commits with their object names"
+msgstr "benennt Versionen nach ihren Objektnamen"
+
+#: builtin/show-branch.c:666
+msgid "show possible merge bases"
+msgstr "zeigt mögliche Basen für Zusammenführung"
+
+#: builtin/show-branch.c:668
+msgid "show refs unreachable from any other ref"
+msgstr "zeigt Referenzen die unerreichbar von allen anderen Referenzen sind"
+
+#: builtin/show-branch.c:670
+msgid "show commits in topological order"
+msgstr "zeigt Versionen in topologischer Ordnung"
+
+#: builtin/show-branch.c:672
+msgid "show only commits not on the first branch"
+msgstr "zeigt nur Versionen, die sich nicht im ersten Zweig befinden"
+
+#: builtin/show-branch.c:674
+msgid "show merges reachable from only one tip"
+msgstr ""
+"zeigt Zusammenführungen, die nur von einer Zweigspitze aus erreichbar sind"
+
+#: builtin/show-branch.c:676
+msgid "show commits where no parent comes before its children"
+msgstr "zeigt Versionen, wo kein Elternteil vor seinem Kind kommt"
+
+#: builtin/show-branch.c:678
+msgid "<n>[,<base>]"
+msgstr "<n>[,<Basis>]"
+
+#: builtin/show-branch.c:679
+msgid "show <n> most recent ref-log entries starting at base"
+msgstr ""
+"zeigt die <n> jüngsten Einträge im Referenzprotokoll beginnend an der Basis"
+
+#: builtin/show-ref.c:10
+msgid ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+msgstr ""
+"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash"
+"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "
+
+#: builtin/show-ref.c:11
+msgid "git show-ref --exclude-existing[=pattern] < ref-list"
+msgstr "git show-ref --exclude-existing[=Muster] < ref-list"
+
+#: builtin/show-ref.c:165
+msgid "only show tags (can be combined with heads)"
+msgstr "zeigt nur Markierungen (kann mit \"heads\" kombiniert werden)"
+
+#: builtin/show-ref.c:166
+msgid "only show heads (can be combined with tags)"
+msgstr "zeigt nur Zweigspitzen (kann mit \"tags\" kombiniert werden)"
+
+#: builtin/show-ref.c:167
+msgid "stricter reference checking, requires exact ref path"
+msgstr "strengere Referenzprüfung, erfordert exakten Referenzpfad"
+
+#: builtin/show-ref.c:170 builtin/show-ref.c:172
+msgid "show the HEAD reference"
+msgstr "zeigt Referenz der Zweigspitze (HEAD)"
+
+#: builtin/show-ref.c:174
+msgid "dereference tags into object IDs"
+msgstr "dereferenziert Markierungen in Objekt-Identifikationen"
+
+#: builtin/show-ref.c:176
+msgid "only show SHA1 hash using <n> digits"
+msgstr "zeigt nur SHA1 Hash mit <n> Ziffern"
+
+#: builtin/show-ref.c:180
+msgid "do not print results to stdout (useful with --verify)"
+msgstr ""
+"keine Ausgabe der Ergebnisse in die Standard-Ausgabe (nützlich mit --verify)"
+
+#: builtin/show-ref.c:182
+msgid "show refs from stdin that aren't in local repository"
+msgstr ""
+"zeigt Referenzen von der Standard-Eingabe, die sich nicht im lokalen "
+"Projektarchiv befinden, an"
+
+#: builtin/symbolic-ref.c:7
+msgid "git symbolic-ref [options] name [ref]"
+msgstr "git symbolic-ref [Optionen] name [ref]"
+
+#: builtin/symbolic-ref.c:8
+msgid "git symbolic-ref -d [-q] name"
+msgstr "git symbolic-ref -d [-q] name"
+
+#: builtin/symbolic-ref.c:40
+msgid "suppress error message for non-symbolic (detached) refs"
+msgstr ""
+"unterdrückt Fehlermeldungen für nicht-symbolische (losgelöste) Referenzen"
+
+#: builtin/symbolic-ref.c:41
+msgid "delete symbolic ref"
+msgstr "löscht symbolische Referenzen"
+
+#: builtin/symbolic-ref.c:42
+msgid "shorten ref output"
+msgstr "verkürzte Ausgabe der Referenzen"
+
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
+msgid "reason"
+msgstr "Grund"
+
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
+msgid "reason of the update"
+msgstr "Grund für die Aktualisierung"
+
+#: builtin/tag.c:22
+msgid ""
+"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"
+msgstr ""
+"git tag [-a|-s|-u <Schlüssel-id>] [-f] [-m <Nachricht>|-F <Datei>] "
+"<Markierungsname> [<Zweig>]"
+
+#: builtin/tag.c:23
+msgid "git tag -d <tagname>..."
+msgstr "git tag -d <Markierungsname>..."
+
+#: builtin/tag.c:24
+msgid ""
+"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n"
+"\t\t[<pattern>...]"
+msgstr ""
+"git tag -l [-n[<Nummer>]] [--contains <Version>] [--points-at <Objekt>] \n"
+"\t\t[<Muster>...]"
+
+#: builtin/tag.c:26
+msgid "git tag -v <tagname>..."
+msgstr "git tag -v <Markierungsname>..."
+
 #: builtin/tag.c:60
 #, c-format
 msgid "malformed object at '%s'"
@@ -5160,6 +8388,62 @@ msgstr "Option 'points-at' erfordert ein Objekt"
 msgid "malformed object name '%s'"
 msgstr "fehlerhafter Objekt-Name '%s'"
 
+#: builtin/tag.c:447
+msgid "list tag names"
+msgstr "listet Markierungsnamen auf"
+
+#: builtin/tag.c:449
+msgid "print <n> lines of each tag message"
+msgstr "zeigt <n> Zeilen jeder Markierungsbeschreibung"
+
+#: builtin/tag.c:451
+msgid "delete tags"
+msgstr "löscht Markierungen"
+
+#: builtin/tag.c:452
+msgid "verify tags"
+msgstr "überprüft Markierungen"
+
+#: builtin/tag.c:454
+msgid "Tag creation options"
+msgstr "Optionen für Erstellung von Markierungen"
+
+#: builtin/tag.c:456
+msgid "annotated tag, needs a message"
+msgstr "annotierte Markierung, benötigt eine Beschreibung"
+
+#: builtin/tag.c:458
+msgid "tag message"
+msgstr "Markierungsbeschreibung"
+
+#: builtin/tag.c:460
+msgid "annotated and GPG-signed tag"
+msgstr "annotierte und GPG-signierte Markierung"
+
+#: builtin/tag.c:464
+msgid "use another key to sign the tag"
+msgstr "benutzt einen anderen Schlüssel um die Markierung zu signieren"
+
+#: builtin/tag.c:465
+msgid "replace the tag if exists"
+msgstr "ersetzt die Markierung, wenn sie existiert"
+
+#: builtin/tag.c:466
+msgid "show tag list in columns"
+msgstr "zeigt Liste der Markierungen in Spalten"
+
+#: builtin/tag.c:468
+msgid "Tag listing options"
+msgstr "Optionen für Auflistung der Markierungen"
+
+#: builtin/tag.c:471
+msgid "print only tags that contain the commit"
+msgstr "gibt nur Markierungen aus, die diese Version beinhalten"
+
+#: builtin/tag.c:477
+msgid "print only tags of the object"
+msgstr "gibt nur Markierungen von dem Objekt aus"
+
 #: builtin/tag.c:506
 msgid "--column and -n are incompatible"
 msgstr "--column und -n sind inkompatibel"
@@ -5209,27 +8493,191 @@ msgstr "%s: kann Referenz nicht aktualisieren"
 msgid "Updated tag '%s' (was %s)\n"
 msgstr "Aktualisierte Markierung '%s' (war %s)\n"
 
-#: git.c:16
-msgid "See 'git help <command>' for more information on a specific command."
+#: builtin/update-index.c:401
+msgid "git update-index [options] [--] [<file>...]"
+msgstr "git update-index [Optionen] [--] [<Datei>...]"
+
+#: builtin/update-index.c:718
+msgid "continue refresh even when index needs update"
 msgstr ""
-"Siehe 'git help <Kommando>' für weitere Informationen zu einem spezifischen "
-"Kommando"
+"Aktualisierung fortsetzen, auch wenn die Bereitstellung aktualisiert werden "
+"muss"
 
-#: parse-options.h:133 parse-options.h:235
-msgid "n"
-msgstr "Anzahl"
+#: builtin/update-index.c:721
+msgid "refresh: ignore submodules"
+msgstr "Aktualisierung: ignoriert Unterprojekte"
 
-#: parse-options.h:141
-msgid "time"
-msgstr "Zeit"
+#: builtin/update-index.c:724
+msgid "do not ignore new files"
+msgstr "ignoriert keine neuen Dateien"
 
-#: parse-options.h:149
-msgid "file"
-msgstr "Datei"
+#: builtin/update-index.c:726
+msgid "let files replace directories and vice-versa"
+msgstr "lässt Dateien Verzeichnisse ersetzen, und umgedreht"
 
-#: parse-options.h:151
-msgid "when"
-msgstr "wann"
+#: builtin/update-index.c:728
+msgid "notice files missing from worktree"
+msgstr "beachtet fehlende Dateien im Arbeitsbaum"
+
+#: builtin/update-index.c:730
+msgid "refresh even if index contains unmerged entries"
+msgstr ""
+"aktualisiert, auch wenn die Bereitstellung nicht zusammengeführte Einträge "
+"beinhaltet"
+
+#: builtin/update-index.c:733
+msgid "refresh stat information"
+msgstr "aktualisiert Dateiinformationen"
+
+#: builtin/update-index.c:737
+msgid "like --refresh, but ignore assume-unchanged setting"
+msgstr "wie --refresh, ignoriert aber \"assume-unchanged\" Einstellung"
+
+#: builtin/update-index.c:741
+msgid "<mode> <object> <path>"
+msgstr "<Modus> <Objekt> <Pfad>"
+
+#: builtin/update-index.c:742
+msgid "add the specified entry to the index"
+msgstr "stellt den angegebenen Eintrag zur Eintragung bereit"
+
+#: builtin/update-index.c:746
+msgid "(+/-)x"
+msgstr "(+/-)x"
+
+#: builtin/update-index.c:747
+msgid "override the executable bit of the listed files"
+msgstr "überschreibt das \"ausführbar\"-Bit der aufgelisteten Dateien"
+
+#: builtin/update-index.c:751
+msgid "mark files as \"not changing\""
+msgstr "betrachte diese Datei immer als unverändert"
+
+#: builtin/update-index.c:754
+msgid "clear assumed-unchanged bit"
+msgstr "löscht \"assumed-unchanged\"-Bit"
+
+#: builtin/update-index.c:757
+msgid "mark files as \"index-only\""
+msgstr "markiert Dateien als \"index-only\""
+
+#: builtin/update-index.c:760
+msgid "clear skip-worktree bit"
+msgstr "löscht \"skip-worktree\"-Bit"
+
+#: builtin/update-index.c:763
+msgid "add to index only; do not add content to object database"
+msgstr ""
+"fügt nur der Bereitstellung hinzu; Inhalt wird nicht der Objekt-Datenbank "
+"hinzugefügt"
+
+#: builtin/update-index.c:765
+msgid "remove named paths even if present in worktree"
+msgstr "löscht benannte Pfade, auch wenn sie sich im Arbeitsbaum befinden"
+
+#: builtin/update-index.c:767
+msgid "with --stdin: input lines are terminated by null bytes"
+msgstr "mit --stdin: eingegebene Zeilen sind durch NUL-Bytes abgeschlossen"
+
+#: builtin/update-index.c:769
+msgid "read list of paths to be updated from standard input"
+msgstr "liest Liste der zu aktualisierenden Pfade von der Standard-Eingabe"
+
+#: builtin/update-index.c:773
+msgid "add entries from standard input to the index"
+msgstr "fügt Einträge von der Standard-Eingabe der Bereitstellung hinzu"
+
+#: builtin/update-index.c:777
+msgid "repopulate stages #2 and #3 for the listed paths"
+msgstr ""
+"wiederholtes Einpflegen der Zustände #2 und #3 für die aufgelisteten Pfade"
+
+#: builtin/update-index.c:781
+msgid "only update entries that differ from HEAD"
+msgstr ""
+"aktualisiert nur Einträge, die unterschiedlich zur Zweigspitze (HEAD) sind"
+
+#: builtin/update-index.c:785
+msgid "ignore files missing from worktree"
+msgstr "ignoriert fehlende Dateien im Arbeitsbaum"
+
+#: builtin/update-index.c:788
+msgid "report actions to standard output"
+msgstr "gibt die Aktionen in der Standard-Ausgabe aus"
+
+#: builtin/update-index.c:790
+msgid "(for porcelains) forget saved unresolved conflicts"
+msgstr "(für Fremdprogramme) keine gespeicherten, nicht aufgelöste Konflikte"
+
+#: builtin/update-index.c:794
+msgid "write index in this format"
+msgstr "schreibt Bereitstellungsdatei in diesem Format"
+
+#: builtin/update-ref.c:7
+msgid "git update-ref [options] -d <refname> [<oldval>]"
+msgstr "git update-ref [Optionen] -d <Referenzname> [<alterWert>]"
+
+#: builtin/update-ref.c:8
+msgid "git update-ref [options]    <refname> <newval> [<oldval>]"
+msgstr "git update-ref [Optionen]    <Referenzname> <neuerWert> [<alterWert>]"
+
+#: builtin/update-ref.c:19
+msgid "delete the reference"
+msgstr "löscht diese Referenz"
+
+#: builtin/update-ref.c:21
+msgid "update <refname> not the one it points to"
+msgstr "aktualisiert <Referenzname>, nicht den Verweis"
+
+#: builtin/update-server-info.c:6
+msgid "git update-server-info [--force]"
+msgstr "git update-server-info [--force]"
+
+#: builtin/update-server-info.c:14
+msgid "update the info files from scratch"
+msgstr "aktualisiert die Informationsdateien von Grund auf"
+
+#: builtin/verify-pack.c:56
+msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
+msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <Paket>..."
+
+#: builtin/verify-pack.c:66
+msgid "verbose"
+msgstr "erweiterte Ausgaben"
+
+#: builtin/verify-pack.c:68
+msgid "show statistics only"
+msgstr "zeigt nur Statistiken"
+
+#: builtin/verify-tag.c:17
+msgid "git verify-tag [-v|--verbose] <tag>..."
+msgstr "git verify-tag [-v|--verbose] <Markierung>..."
+
+#: builtin/verify-tag.c:73
+msgid "print tag contents"
+msgstr "gibt Markierungsinhalte aus"
+
+#: builtin/write-tree.c:13
+msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
+msgstr "git write-tree [--missing-ok] [--prefix=<Prefix>/]"
+
+#: builtin/write-tree.c:26
+msgid "<prefix>/"
+msgstr "<Prefix>/"
+
+#: builtin/write-tree.c:27
+msgid "write tree object for a subdirectory <prefix>"
+msgstr "schreibt das Baumobjekt für ein Unterverzeichnis <Prefix>"
+
+#: builtin/write-tree.c:30
+msgid "only useful for debugging"
+msgstr "nur nützlich für Fehlersuche"
+
+#: git.c:16
+msgid "See 'git help <command>' for more information on a specific command."
+msgstr ""
+"Siehe 'git help <Kommando>' für weitere Informationen zu einem spezifischen "
+"Kommando"
 
 #: parse-options.h:156
 msgid "no-op (backward compatibility)"
@@ -5457,7 +8905,7 @@ msgstr ""
 
 #: git-am.sh:706
 msgid "Patch does not have a valid e-mail address."
-msgstr "Patch enthält keine gültige eMail-Adresse."
+msgstr "Patch enthält keine gültige Email-Adresse."
 
 #: git-am.sh:753
 msgid "cannot be interactive without stdin connected to a terminal."
@@ -5509,6 +8957,15 @@ msgstr "Keine Änderungen -- Patches bereits angewendet."
 msgid "Patch failed at $msgnum $FIRSTLINE"
 msgstr "Anwendung des Patches fehlgeschlagen bei $msgnum $FIRSTLINE"
 
+#: git-am.sh:858
+#, sh-format
+msgid ""
+"The copy of the patch that failed is found in:\n"
+"   $dotest/patch"
+msgstr ""
+"Die Kopie des fehlgeschlagenen Patches befindet sich in:\n"
+"   $dotest/patch"
+
 #: git-am.sh:876
 msgid "applying to an empty history"
 msgstr "wende zu leerer Historie an"
@@ -5696,7 +9153,7 @@ msgstr ""
 #. The working tree and the index file is still based on the
 #. $orig_head commit, but we are merging into $curr_head.
 #. First update the working tree to match $curr_head.
-#: git-pull.sh:228
+#: git-pull.sh:229
 #, sh-format
 msgid ""
 "Warning: fetch updated the current branch head.\n"
@@ -5706,15 +9163,15 @@ msgstr ""
 "Warnung: Die Anforderung aktualisierte die Spitze des aktuellen Zweiges.\n"
 "Warnung: Spule deinen Arbeitszweig von Version $orig_head vor."
 
-#: git-pull.sh:253
+#: git-pull.sh:254
 msgid "Cannot merge multiple branches into empty head"
 msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen"
 
-#: git-pull.sh:257
+#: git-pull.sh:258
 msgid "Cannot rebase onto multiple branches"
 msgstr "kann nicht auf mehrere Zweige neu aufbauen"
 
-#: git-rebase.sh:52
+#: git-rebase.sh:53
 msgid ""
 "When you have resolved this problem, run \"git rebase --continue\".\n"
 "If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
@@ -5728,27 +9185,32 @@ msgstr ""
 "abzubrechen,\n"
 "führe \"git rebase --abort\" aus."
 
-#: git-rebase.sh:159
+#: git-rebase.sh:160
 msgid "The pre-rebase hook refused to rebase."
 msgstr "Der \"pre-rebase hook\" hat den Neuaufbau zurückgewiesen."
 
-#: git-rebase.sh:164
+#: git-rebase.sh:165
 msgid "It looks like git-am is in progress. Cannot rebase."
 msgstr "\"git-am\" scheint im Gange zu sein. Kann nicht neu aufbauen."
 
-#: git-rebase.sh:295
+#: git-rebase.sh:296
 msgid "The --exec option must be used with the --interactive option"
 msgstr "Die --exec Option muss mit der --interactive Option benutzt werden"
 
-#: git-rebase.sh:300
+#: git-rebase.sh:301
 msgid "No rebase in progress?"
 msgstr "Kein Neuaufbau im Gange?"
 
-#: git-rebase.sh:313
+#: git-rebase.sh:312
+msgid "The --edit-todo action can only be used during interactive rebase."
+msgstr "Die --edit-todo Aktion kann nur während eines interaktiven "
+"Neuaufbaus benutzt werden."
+
+#: git-rebase.sh:319
 msgid "Cannot read HEAD"
 msgstr "Kann Zweigspitze (HEAD) nicht lesen"
 
-#: git-rebase.sh:316
+#: git-rebase.sh:322
 msgid ""
 "You must edit all merge conflicts and then\n"
 "mark them as resolved using git add"
@@ -5756,12 +9218,12 @@ msgstr ""
 "Du musst alle Zusammenführungskonflikte editieren und diese dann\n"
 "mittels \"git add\" als aufgelöst markieren"
 
-#: git-rebase.sh:334
+#: git-rebase.sh:340
 #, sh-format
 msgid "Could not move back to $head_name"
 msgstr "Konnte nicht zu $head_name zurückgehen"
 
-#: git-rebase.sh:350
+#: git-rebase.sh:359
 #, sh-format
 msgid ""
 "It seems that there is already a $state_dir_base directory, and\n"
@@ -5782,59 +9244,59 @@ msgstr ""
 "und führe dieses Kommando nochmal aus. Es wird angehalten, falls noch\n"
 "etwas Schützenswertes vorhanden ist."
 
-#: git-rebase.sh:395
+#: git-rebase.sh:404
 #, sh-format
 msgid "invalid upstream $upstream_name"
 msgstr "ungültiger Übernahmezweig $upstream_name"
 
-#: git-rebase.sh:419
+#: git-rebase.sh:428
 #, sh-format
 msgid "$onto_name: there are more than one merge bases"
 msgstr "$onto_name: es gibt mehr als eine Zusammenführungsbasis"
 
-#: git-rebase.sh:422 git-rebase.sh:426
+#: git-rebase.sh:431 git-rebase.sh:435
 #, sh-format
 msgid "$onto_name: there is no merge base"
 msgstr "$onto_name: es gibt keine Zusammenführungsbasis"
 
-#: git-rebase.sh:431
+#: git-rebase.sh:440
 #, sh-format
 msgid "Does not point to a valid commit: $onto_name"
 msgstr "$onto_name zeigt auf keine gültige Version"
 
-#: git-rebase.sh:454
+#: git-rebase.sh:463
 #, sh-format
 msgid "fatal: no such branch: $branch_name"
 msgstr "fatal: Zweig $branch_name nicht gefunden"
 
-#: git-rebase.sh:474
+#: git-rebase.sh:483
 msgid "Please commit or stash them."
 msgstr "Bitte trage die Änderungen ein oder benutze \"stash\"."
 
-#: git-rebase.sh:492
+#: git-rebase.sh:501
 #, sh-format
 msgid "Current branch $branch_name is up to date."
 msgstr "Aktueller Zweig $branch_name ist auf dem neusten Stand."
 
-#: git-rebase.sh:495
+#: git-rebase.sh:504
 #, sh-format
 msgid "Current branch $branch_name is up to date, rebase forced."
 msgstr ""
 "Aktueller Zweig $branch_name ist auf dem neusten Stand, Neuaufbau erzwungen."
 
-#: git-rebase.sh:506
+#: git-rebase.sh:515
 #, sh-format
 msgid "Changes from $mb to $onto:"
 msgstr "Änderungen von $mb zu $onto:"
 
 #. Detach HEAD and reset the tree
-#: git-rebase.sh:515
+#: git-rebase.sh:524
 msgid "First, rewinding head to replay your work on top of it..."
 msgstr ""
 "Zunächst wird die Zweigspitze zurückgespult, um deine Änderungen\n"
 "darauf neu anzuwenden..."
 
-#: git-rebase.sh:523
+#: git-rebase.sh:532
 #, sh-format
 msgid "Fast-forwarded $branch_name to $onto_name."
 msgstr "$branch_name zu $onto_name vorgespult."
@@ -5861,7 +9323,7 @@ msgstr "Keine Änderungen ausgewählt"
 
 #: git-stash.sh:143
 msgid "Cannot remove temporary index (can't happen)"
-msgstr "Kann temporäre Bereitstellung nicht entfernen (kann nicht passieren)"
+msgstr "Kann temporäre Bereitstellung nicht löschen (kann nicht passieren)"
 
 #: git-stash.sh:156
 msgid "Cannot record working tree state"
@@ -5901,7 +9363,7 @@ msgstr "Kann den aktuellen Status nicht speichern"
 
 #: git-stash.sh:253
 msgid "Cannot remove worktree changes"
-msgstr "Kann Änderungen am Arbeitsbaum nicht entfernen"
+msgstr "Kann Änderungen am Arbeitsbaum nicht löschen"
 
 #: git-stash.sh:352
 msgid "No stash found."
@@ -5948,34 +9410,34 @@ msgstr "Konnte Bereitstellungsbaum nicht speichern"
 msgid "Cannot unstage modified files"
 msgstr "Kann geänderte Dateien nicht aus der Bereitstellung herausnehmen"
 
-#: git-stash.sh:474
+#: git-stash.sh:475
 msgid "Index was not unstashed."
 msgstr "Bereitstellung wurde nicht ausgelagert."
 
-#: git-stash.sh:491
+#: git-stash.sh:492
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Gelöscht ${REV} ($s)"
 
-#: git-stash.sh:492
+#: git-stash.sh:493
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen"
 
-#: git-stash.sh:499
+#: git-stash.sh:500
 msgid "No branch name specified"
 msgstr "Kein Zweigname spezifiziert"
 
-#: git-stash.sh:570
+#: git-stash.sh:571
 msgid "(To restore them type \"git stash apply\")"
 msgstr "(Zur Wiederherstellung gebe \"git stash apply\" ein)"
 
-#: git-submodule.sh:88
+#: git-submodule.sh:89
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
 msgstr "Kann eine Komponente von URL '$remoteurl' nicht extrahieren"
 
-#: git-submodule.sh:167
+#: git-submodule.sh:168
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
@@ -5992,17 +9454,17 @@ msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
 msgstr ""
 "Git-Verzeichnis '$a' ist Teil des Unterprojekt-Pfades '$b', oder umgekehrt"
 
-#: git-submodule.sh:312
+#: git-submodule.sh:316
 #, sh-format
 msgid "repo URL: '$repo' must be absolute or begin with ./|../"
 msgstr "repo URL: '$repo' muss absolut sein oder mit ./|../ beginnen"
 
-#: git-submodule.sh:329
+#: git-submodule.sh:333
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr "'$sm_path' existiert bereits in der Bereitstellung"
 
-#: git-submodule.sh:333
+#: git-submodule.sh:337
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -6013,65 +9475,101 @@ msgstr ""
 "$sm_path\n"
 "Benutze -f wenn du diesen wirklich hinzufügen möchtest."
 
-#: git-submodule.sh:344
+#: git-submodule.sh:355
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
 msgstr ""
 "Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung hinzu."
 
-#: git-submodule.sh:346
+#: git-submodule.sh:357
 #, sh-format
 msgid "'$sm_path' already exists and is not a valid git repo"
 msgstr "'$sm_path' existiert bereits und ist kein gültiges Git-Projektarchiv"
 
-#: git-submodule.sh:360
+#: git-submodule.sh:365
+#, sh-format
+msgid "A git directory for '$sm_name' is found locally with remote(s):"
+msgstr "Ein Git-Verzeichnis für '$sm_name' wurde lokal gefunden mit den "
+"Fernarchiv(en):"
+
+#: git-submodule.sh:367
+#, sh-format
+msgid ""
+"If you want to reuse this local git directory instead of cloning again from"
+msgstr ""
+"Wenn du dieses lokale Git-Verzeichnis wiederverwenden möchtest, anstatt "
+"erneut zu klonen"
+
+#: git-submodule.sh:369
+#, sh-format
+msgid ""
+"use the '--force' option. If the local git directory is not the correct repo"
+msgstr ""
+"benutze die Option '--force'. Wenn das lokale Git-Verzeichnis nicht das "
+"korrekte Projektarchiv ist"
+
+#: git-submodule.sh:370
+#, sh-format
+msgid ""
+"or you are unsure what this means choose another name with the '--name' "
+"option."
+msgstr ""
+"oder du dir unsicher bist, was das bedeutet, wähle einen anderen Namen mit "
+"der Option '--name'."
+
+#: git-submodule.sh:372
+#, sh-format
+msgid "Reactivating local git directory for submodule '$sm_name'."
+msgstr "Reaktiviere lokales Git-Verzeichnis für Unterprojekt '$sm_name'."
+
+#: git-submodule.sh:384
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Unfähig Unterprojekt '$sm_path' auszuchecken"
 
-#: git-submodule.sh:365
+#: git-submodule.sh:389
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr "Hinzufügen von Unterprojekt '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:370
+#: git-submodule.sh:394
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr "Registierung von Unterprojekt '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:413
+#: git-submodule.sh:437
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr "Betrete '$prefix$sm_path'"
 
-#: git-submodule.sh:427
+#: git-submodule.sh:451
 #, sh-format
 msgid "Stopping at '$sm_path'; script returned non-zero status."
 msgstr "Stoppe bei '$sm_path'; Skript gab nicht-Null Status zurück."
 
-#: git-submodule.sh:471
+#: git-submodule.sh:495
 #, sh-format
 msgid "No url found for submodule path '$sm_path' in .gitmodules"
 msgstr "Keine URL für Unterprojekt-Pfad '$sm_path' in .gitmodules gefunden"
 
-#: git-submodule.sh:480
+#: git-submodule.sh:504
 #, sh-format
 msgid "Failed to register url for submodule path '$sm_path'"
 msgstr "Registrierung der URL für Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:482
+#: git-submodule.sh:506
 #, sh-format
 msgid "Submodule '$name' ($url) registered for path '$sm_path'"
 msgstr "Unterprojekt '$name' ($url) ist für Pfad '$sm_path' registriert"
 
-#: git-submodule.sh:490
+#: git-submodule.sh:514
 #, sh-format
 msgid "Failed to register update mode for submodule path '$sm_path'"
 msgstr ""
 "Registrierung des Aktualisierungsmodus für Unterprojekt-Pfad '$sm_path' "
 "fehlgeschlagen"
 
-#: git-submodule.sh:590
+#: git-submodule.sh:614
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
@@ -6080,94 +9578,150 @@ msgstr ""
 "Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n"
 "Vielleicht möchtest du 'update --init' benutzen?"
 
-#: git-submodule.sh:603
+#: git-submodule.sh:627
 #, sh-format
 msgid "Unable to find current revision in submodule path '$sm_path'"
 msgstr "Konnte aktuelle Version in Unterprojekt-Pfad '$sm_path' nicht finden"
 
-#: git-submodule.sh:622
+#: git-submodule.sh:646
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr "Konnte in Unterprojekt-Pfad '$sm_path' nicht anfordern"
 
-#: git-submodule.sh:636
+#: git-submodule.sh:660
 #, sh-format
 msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
 msgstr "Neuaufbau von '$sha1' in Unterprojekt-Pfad '$sm_path' nicht möglich"
 
-#: git-submodule.sh:637
+#: git-submodule.sh:661
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr "Unterprojekt-Pfad '$sm_path': neu aufgebaut in '$sha1'"
 
-#: git-submodule.sh:642
+#: git-submodule.sh:666
 #, sh-format
 msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
 msgstr ""
 "Zusammenführung von '$sha1' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen"
 
-#: git-submodule.sh:643
+#: git-submodule.sh:667
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr "Unterprojekt-Pfad '$sm_path': zusammengeführt in '$sha1'"
 
-#: git-submodule.sh:648
+#: git-submodule.sh:672
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
 msgstr "Konnte '$sha1' in Unterprojekt-Pfad '$sm_path' nicht auschecken."
 
-#: git-submodule.sh:649
+#: git-submodule.sh:673
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr "Unterprojekt-Pfad: '$sm_path': '$sha1' ausgecheckt"
 
-#: git-submodule.sh:671 git-submodule.sh:995
+#: git-submodule.sh:695 git-submodule.sh:1017
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$sm_path'"
 
-#: git-submodule.sh:779
+#: git-submodule.sh:803
 msgid "The --cached option cannot be used with the --files option"
 msgstr "Die --cached Option kann nicht mit der --files Option benutzt werden"
 
 #. unexpected type
-#: git-submodule.sh:819
+#: git-submodule.sh:843
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "unerwarteter Modus $mod_dst"
 
-#: git-submodule.sh:837
+#: git-submodule.sh:861
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr "  Warnung: $name beinhaltet nicht Version $sha1_src"
 
-#: git-submodule.sh:840
+#: git-submodule.sh:864
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr "  Warnung: $name beinhaltet nicht Version $sha1_dst"
 
-#: git-submodule.sh:843
+#: git-submodule.sh:867
 #, sh-format
 msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 msgstr ""
 "  Warnung: $name beinhaltet nicht die Versionen $sha1_src und $sha1_dst"
 
-#: git-submodule.sh:868
+#: git-submodule.sh:892
 msgid "blob"
 msgstr "Blob"
 
-#: git-submodule.sh:906
+#: git-submodule.sh:930
 msgid "# Submodules changed but not updated:"
 msgstr "# Unterprojekte geändert, aber nicht aktualisiert:"
 
-#: git-submodule.sh:908
+#: git-submodule.sh:932
 msgid "# Submodule changes to be committed:"
 msgstr "# Änderungen in Unterprojekt zum Eintragen:"
 
-#: git-submodule.sh:1054
+#: git-submodule.sh:1080
 #, sh-format
-msgid "Synchronizing submodule url for '$name'"
-msgstr "Synchronisiere Unterprojekt-URL für '$name'"
+msgid "Synchronizing submodule url for '$prefix$sm_path'"
+msgstr "Synchronisiere Unterprojekt-URL für '$prefix$sm_path'"
+
+#~ msgid " 0 files changed"
+#~ msgstr " 0 Dateien geändert"
+
+#~ msgid " %d file changed"
+#~ msgid_plural " %d files changed"
+#~ msgstr[0] " %d Datei geändert"
+#~ msgstr[1] " %d Dateien geändert"
+
+#~ msgid ", %d insertion(+)"
+#~ msgid_plural ", %d insertions(+)"
+#~ msgstr[0] ", %d Zeile hinzugefügt(+)"
+#~ msgstr[1] ", %d Zeilen hinzugefügt(+)"
+
+#~ msgid ", %d deletion(-)"
+#~ msgid_plural ", %d deletions(-)"
+#~ msgstr[0] ", %d Zeile entfernt(-)"
+#~ msgstr[1] ", %d Zeilen entfernt(-)"
+
+#~ msgid "Auto packing the repository for optimum performance.\n"
+#~ msgstr ""
+#~ "Die Datenbank des Projektarchivs wird für eine optimale Performance "
+#~ "komprimiert.\n"
+
+#~ msgid "git remote set-head <name> (-a | -d | <branch>])"
+#~ msgstr "git remote set-head <Name> (-a | -d | <Zweig>])"
+
+#~ msgid " (use \"git add\" to track)"
+#~ msgstr " (benutze \"git add\" zum Beobachten)"
+
+#~ msgid "-B cannot be used with -b"
+#~ msgstr "-B kann nicht mit -b benutzt werden"
+
+#~ msgid "--patch is incompatible with all other options"
+#~ msgstr "--patch ist inkompatibel mit allen anderen Optionen"
+
+#~ msgid "--detach cannot be used with -b/-B/--orphan"
+#~ msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden"
+
+#~ msgid "--detach cannot be used with -t"
+#~ msgstr "--detach kann nicht mit -t benutzt werden"
+
+#~ msgid "--orphan and -b|-B are mutually exclusive"
+#~ msgstr "--orphan und -b|-B sind gegenseitig exklusiv"
+
+#~ msgid "--orphan cannot be used with -t"
+#~ msgstr "--orphan kann nicht mit -t benutzt werden"
+
+#~ msgid "git checkout: -f and -m are incompatible"
+#~ msgstr "git checkout: -f und -m sind inkompatibel"
+
+#~ msgid ""
+#~ "git checkout: updating paths is incompatible with switching branches."
+#~ msgstr ""
+#~ "git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem "
+#~ "Wechsel von Zweigen."
 
 #~ msgid "diff setup failed"
 #~ msgstr "diff_setup_done fehlgeschlagen"
@@ -6199,9 +9753,6 @@ msgstr "Synchronisiere Unterprojekt-URL für '$name'"
 #~ msgid "Please enter the commit message for your changes."
 #~ msgstr "Bitte gebe die Versionsbeschreibung für deine Änderungen ein."
 
-#~ msgid "Too many options specified"
-#~ msgstr "Zu viele Optionen angegeben"
-
 #~ msgid ""
 #~ "To prevent you from losing history, non-fast-forward updates were "
 #~ "rejected\n"
index e561158..430d033 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-10-16 08:38+0800\n"
+"POT-Creation-Date: 2012-11-30 12:40+0800\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -60,7 +60,7 @@ msgstr ""
 msgid "archive format"
 msgstr ""
 
-#: archive.c:323 builtin/log.c:1079
+#: archive.c:323 builtin/log.c:1084
 msgid "prefix"
 msgstr ""
 
@@ -68,9 +68,9 @@ msgstr ""
 msgid "prepend prefix to each pathname in the archive"
 msgstr ""
 
-#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2389
-#: builtin/blame.c:2390 builtin/config.c:56 builtin/fast-export.c:642
-#: builtin/fast-export.c:644 builtin/grep.c:801 builtin/hash-object.c:77
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390
+#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77
 #: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540
 #: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149
 msgid "file"
@@ -120,6 +120,12 @@ msgstr ""
 msgid "path to the remote git-upload-archive command"
 msgstr ""
 
+#: attr.c:259
+msgid ""
+"Negative patterns are forbidden in git attributes\n"
+"Use '\\!' for literal leading exclamation."
+msgstr ""
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
@@ -130,7 +136,7 @@ msgstr ""
 msgid "unrecognized header: %s%s (%d)"
 msgstr ""
 
-#: bundle.c:89 builtin/commit.c:672
+#: bundle.c:89 builtin/commit.c:674
 #, c-format
 msgid "could not open '%s'"
 msgstr ""
@@ -140,7 +146,7 @@ msgid "Repository lacks these prerequisite commits:"
 msgstr ""
 
 #: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290
-#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
+#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr ""
@@ -167,7 +173,7 @@ msgstr[1] ""
 msgid "rev-list died"
 msgstr ""
 
-#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr ""
@@ -293,30 +299,40 @@ msgid_plural "%lu years ago"
 msgstr[0] ""
 msgstr[1] ""
 
-#: diff.c:105
+#: diff.c:111
+#, c-format
+msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
+msgstr ""
+
+#: diff.c:116
 #, c-format
-msgid "  Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgid "  Unknown dirstat parameter '%s'\n"
 msgstr ""
 
-#: diff.c:110
+#: diff.c:194
 #, c-format
-msgid "  Unknown dirstat parameter '%.*s'\n"
+msgid "Unknown value for 'diff.submodule' config variable: '%s'"
 msgstr ""
 
-#: diff.c:210
+#: diff.c:237
 #, c-format
 msgid ""
 "Found errors in 'diff.dirstat' config variable:\n"
 "%s"
 msgstr ""
 
-#: diff.c:3458
+#: diff.c:3494
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
 "%s"
 msgstr ""
 
+#: diff.c:3508
+#, c-format
+msgid "Failed to parse --submodule option parameter: '%s'"
+msgstr ""
+
 #: gpg-interface.c:59
 msgid "could not run gpg."
 msgstr ""
@@ -329,17 +345,17 @@ msgstr ""
 msgid "gpg failed to sign the data"
 msgstr ""
 
-#: grep.c:1441
+#: grep.c:1622
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr ""
 
-#: grep.c:1458
+#: grep.c:1639
 #, c-format
 msgid "'%s': %s"
 msgstr ""
 
-#: grep.c:1469
+#: grep.c:1650
 #, c-format
 msgid "'%s': short read %s"
 msgstr ""
@@ -391,6 +407,15 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
+#: merge.c:56
+msgid "failed to read the cache"
+msgstr ""
+
+#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
+#: builtin/clone.c:586
+msgid "unable to write new index file"
+msgstr ""
+
 #: merge-recursive.c:190
 #, c-format
 msgid "(bad commit)\n"
@@ -563,7 +588,7 @@ msgstr ""
 msgid "Auto-merging %s"
 msgstr ""
 
-#: merge-recursive.c:1633 git-submodule.sh:869
+#: merge-recursive.c:1633 git-submodule.sh:893
 msgid "submodule"
 msgstr ""
 
@@ -633,7 +658,7 @@ msgstr ""
 msgid "Could not parse object '%s'"
 msgstr ""
 
-#: merge-recursive.c:2009 builtin/merge.c:696
+#: merge-recursive.c:2009 builtin/merge.c:643
 msgid "Unable to write index."
 msgstr ""
 
@@ -665,7 +690,11 @@ msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
 msgstr[0] ""
 msgstr[1] ""
 
-#: remote.c:1638
+#: remote.c:1637
+msgid "  (use \"git push\" to publish your local commits)\n"
+msgstr ""
+
+#: remote.c:1640
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -673,7 +702,11 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
-#: remote.c:1646
+#: remote.c:1647
+msgid "  (use \"git pull\" to update your local branch)\n"
+msgstr ""
+
+#: remote.c:1650
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -684,14 +717,18 @@ msgid_plural ""
 msgstr[0] ""
 msgstr[1] ""
 
-#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
-#: builtin/merge.c:1087 builtin/merge.c:1097
+#: remote.c:1659
+msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
+msgstr ""
+
+#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
+#: builtin/merge.c:994
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr ""
 
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
-#: builtin/merge.c:1089 builtin/merge.c:1102
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
+#: builtin/merge.c:999
 #, c-format
 msgid "Could not write to '%s'"
 msgstr ""
@@ -1299,7 +1336,7 @@ msgstr ""
 msgid "unexpected diff status %c"
 msgstr ""
 
-#: builtin/add.c:67 builtin/commit.c:230
+#: builtin/add.c:67 builtin/commit.c:231
 msgid "updating files failed"
 msgstr ""
 
@@ -1317,7 +1354,7 @@ msgstr ""
 msgid "Unstaged changes after refreshing the index:"
 msgstr ""
 
-#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr ""
@@ -1360,12 +1397,12 @@ msgstr ""
 
 #: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
 #: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
-#: builtin/rm.c:133
+#: builtin/rm.c:206
 msgid "dry run"
 msgstr ""
 
-#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1154
-#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483
 #: builtin/mv.c:62 builtin/read-tree.c:112
 msgid "be verbose"
 msgstr ""
@@ -1374,7 +1411,7 @@ msgstr ""
 msgid "interactive picking"
 msgstr ""
 
-#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248
 msgid "select hunks interactively"
 msgstr ""
 
@@ -1441,12 +1478,12 @@ msgstr ""
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr ""
 
-#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
-#: builtin/rm.c:162
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82
+#: builtin/rm.c:235
 msgid "index file corrupt"
 msgstr ""
 
-#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370
 msgid "Unable to write new index file"
 msgstr ""
 
@@ -1975,95 +2012,95 @@ msgstr ""
 msgid "[rev-opts] are documented in git-rev-list(1)"
 msgstr ""
 
-#: builtin/blame.c:2373
+#: builtin/blame.c:2374
 msgid "Show blame entries as we find them, incrementally"
 msgstr ""
 
-#: builtin/blame.c:2374
+#: builtin/blame.c:2375
 msgid "Show blank SHA-1 for boundary commits (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2375
+#: builtin/blame.c:2376
 msgid "Do not treat root commits as boundaries (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2376
+#: builtin/blame.c:2377
 msgid "Show work cost statistics"
 msgstr ""
 
-#: builtin/blame.c:2377
+#: builtin/blame.c:2378
 msgid "Show output score for blame entries"
 msgstr ""
 
-#: builtin/blame.c:2378
+#: builtin/blame.c:2379
 msgid "Show original filename (Default: auto)"
 msgstr ""
 
-#: builtin/blame.c:2379
+#: builtin/blame.c:2380
 msgid "Show original linenumber (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2380
+#: builtin/blame.c:2381
 msgid "Show in a format designed for machine consumption"
 msgstr ""
 
-#: builtin/blame.c:2381
+#: builtin/blame.c:2382
 msgid "Show porcelain format with per-line commit information"
 msgstr ""
 
-#: builtin/blame.c:2382
+#: builtin/blame.c:2383
 msgid "Use the same output mode as git-annotate (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2383
+#: builtin/blame.c:2384
 msgid "Show raw timestamp (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2384
+#: builtin/blame.c:2385
 msgid "Show long commit SHA1 (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2385
+#: builtin/blame.c:2386
 msgid "Suppress author name and timestamp (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2386
+#: builtin/blame.c:2387
 msgid "Show author email instead of name (Default: off)"
 msgstr ""
 
-#: builtin/blame.c:2387
+#: builtin/blame.c:2388
 msgid "Ignore whitespace differences"
 msgstr ""
 
-#: builtin/blame.c:2388
+#: builtin/blame.c:2389
 msgid "Spend extra cycles to find better match"
 msgstr ""
 
-#: builtin/blame.c:2389
+#: builtin/blame.c:2390
 msgid "Use revisions from <file> instead of calling git-rev-list"
 msgstr ""
 
-#: builtin/blame.c:2390
+#: builtin/blame.c:2391
 msgid "Use <file>'s contents as the final image"
 msgstr ""
 
-#: builtin/blame.c:2391 builtin/blame.c:2392
+#: builtin/blame.c:2392 builtin/blame.c:2393
 msgid "score"
 msgstr ""
 
-#: builtin/blame.c:2391
+#: builtin/blame.c:2392
 msgid "Find line copies within and across files"
 msgstr ""
 
-#: builtin/blame.c:2392
+#: builtin/blame.c:2393
 msgid "Find line movements within and across files"
 msgstr ""
 
-#: builtin/blame.c:2393
+#: builtin/blame.c:2394
 msgid "n,m"
 msgstr ""
 
-#: builtin/blame.c:2393
+#: builtin/blame.c:2394
 msgid "Process only line range n,m, counting from 1"
 msgstr ""
 
@@ -2097,269 +2134,269 @@ msgid ""
 "         '%s', even though it is merged to HEAD."
 msgstr ""
 
-#: builtin/branch.c:181
+#: builtin/branch.c:163
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr ""
+
+#: builtin/branch.c:167
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+
+#: builtin/branch.c:180
+msgid "Update of config-file failed"
+msgstr ""
+
+#: builtin/branch.c:208
 msgid "cannot use -a with -d"
 msgstr ""
 
-#: builtin/branch.c:187
+#: builtin/branch.c:214
 msgid "Couldn't look up commit object for HEAD"
 msgstr ""
 
-#: builtin/branch.c:192
+#: builtin/branch.c:222
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
 msgstr ""
 
-#: builtin/branch.c:203
+#: builtin/branch.c:235
 #, c-format
 msgid "remote branch '%s' not found."
 msgstr ""
 
-#: builtin/branch.c:204
+#: builtin/branch.c:236
 #, c-format
 msgid "branch '%s' not found."
 msgstr ""
 
-#: builtin/branch.c:211
-#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr ""
-
-#: builtin/branch.c:217
-#, c-format
-msgid ""
-"The branch '%s' is not fully merged.\n"
-"If you are sure you want to delete it, run 'git branch -D %s'."
-msgstr ""
-
-#: builtin/branch.c:226
+#: builtin/branch.c:250
 #, c-format
 msgid "Error deleting remote branch '%s'"
 msgstr ""
 
-#: builtin/branch.c:227
+#: builtin/branch.c:251
 #, c-format
 msgid "Error deleting branch '%s'"
 msgstr ""
 
-#: builtin/branch.c:234
+#: builtin/branch.c:258
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr ""
 
-#: builtin/branch.c:235
+#: builtin/branch.c:259
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr ""
 
-#: builtin/branch.c:240
-msgid "Update of config-file failed"
-msgstr ""
-
-#: builtin/branch.c:338
+#: builtin/branch.c:361
 #, c-format
 msgid "branch '%s' does not point at a commit"
 msgstr ""
 
-#: builtin/branch.c:410
+#: builtin/branch.c:433
 #, c-format
 msgid "[%s: behind %d]"
 msgstr ""
 
-#: builtin/branch.c:412
+#: builtin/branch.c:435
 #, c-format
 msgid "[behind %d]"
 msgstr ""
 
-#: builtin/branch.c:416
+#: builtin/branch.c:439
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr ""
 
-#: builtin/branch.c:418
+#: builtin/branch.c:441
 #, c-format
 msgid "[ahead %d]"
 msgstr ""
 
-#: builtin/branch.c:421
+#: builtin/branch.c:444
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr ""
 
-#: builtin/branch.c:424
+#: builtin/branch.c:447
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr ""
 
-#: builtin/branch.c:537
+#: builtin/branch.c:560
 msgid "(no branch)"
 msgstr ""
 
-#: builtin/branch.c:602
+#: builtin/branch.c:625
 msgid "some refs could not be read"
 msgstr ""
 
-#: builtin/branch.c:615
+#: builtin/branch.c:638
 msgid "cannot rename the current branch while not on any."
 msgstr ""
 
-#: builtin/branch.c:625
+#: builtin/branch.c:648
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr ""
 
-#: builtin/branch.c:640
+#: builtin/branch.c:663
 msgid "Branch rename failed"
 msgstr ""
 
-#: builtin/branch.c:644
+#: builtin/branch.c:667
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
 msgstr ""
 
-#: builtin/branch.c:648
+#: builtin/branch.c:671
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr ""
 
-#: builtin/branch.c:655
+#: builtin/branch.c:678
 msgid "Branch is renamed, but update of config-file failed"
 msgstr ""
 
-#: builtin/branch.c:670
+#: builtin/branch.c:693
 #, c-format
 msgid "malformed object name %s"
 msgstr ""
 
-#: builtin/branch.c:694
+#: builtin/branch.c:717
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr ""
 
-#: builtin/branch.c:724
+#: builtin/branch.c:747
 msgid "Generic options"
 msgstr ""
 
-#: builtin/branch.c:726
+#: builtin/branch.c:749
 msgid "show hash and subject, give twice for upstream branch"
 msgstr ""
 
-#: builtin/branch.c:727
+#: builtin/branch.c:750
 msgid "suppress informational messages"
 msgstr ""
 
-#: builtin/branch.c:728
+#: builtin/branch.c:751
 msgid "set up tracking mode (see git-pull(1))"
 msgstr ""
 
-#: builtin/branch.c:730
+#: builtin/branch.c:753
 msgid "change upstream info"
 msgstr ""
 
-#: builtin/branch.c:734
+#: builtin/branch.c:757
 msgid "use colored output"
 msgstr ""
 
-#: builtin/branch.c:735
+#: builtin/branch.c:758
 msgid "act on remote-tracking branches"
 msgstr ""
 
-#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
-#: builtin/branch.c:771 builtin/commit.c:1362 builtin/commit.c:1363
-#: builtin/commit.c:1364 builtin/commit.c:1365 builtin/tag.c:470
+#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
+#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377
+#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470
 msgid "commit"
 msgstr ""
 
-#: builtin/branch.c:739 builtin/branch.c:745
+#: builtin/branch.c:762 builtin/branch.c:768
 msgid "print only branches that contain the commit"
 msgstr ""
 
-#: builtin/branch.c:751
+#: builtin/branch.c:774
 msgid "Specific git-branch actions:"
 msgstr ""
 
-#: builtin/branch.c:752
+#: builtin/branch.c:775
 msgid "list both remote-tracking and local branches"
 msgstr ""
 
-#: builtin/branch.c:754
+#: builtin/branch.c:777
 msgid "delete fully merged branch"
 msgstr ""
 
-#: builtin/branch.c:755
+#: builtin/branch.c:778
 msgid "delete branch (even if not merged)"
 msgstr ""
 
-#: builtin/branch.c:756
+#: builtin/branch.c:779
 msgid "move/rename a branch and its reflog"
 msgstr ""
 
-#: builtin/branch.c:757
+#: builtin/branch.c:780
 msgid "move/rename a branch, even if target exists"
 msgstr ""
 
-#: builtin/branch.c:758
+#: builtin/branch.c:781
 msgid "list branch names"
 msgstr ""
 
-#: builtin/branch.c:759
+#: builtin/branch.c:782
 msgid "create the branch's reflog"
 msgstr ""
 
-#: builtin/branch.c:761
+#: builtin/branch.c:784
 msgid "edit the description for the branch"
 msgstr ""
 
-#: builtin/branch.c:762
+#: builtin/branch.c:785
 msgid "force creation (when already exists)"
 msgstr ""
 
-#: builtin/branch.c:765
+#: builtin/branch.c:788
 msgid "print only not merged branches"
 msgstr ""
 
-#: builtin/branch.c:771
+#: builtin/branch.c:794
 msgid "print only merged branches"
 msgstr ""
 
-#: builtin/branch.c:775
+#: builtin/branch.c:798
 msgid "list branches in columns"
 msgstr ""
 
-#: builtin/branch.c:788
+#: builtin/branch.c:811
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr ""
 
-#: builtin/branch.c:793 builtin/clone.c:561
+#: builtin/branch.c:816 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr ""
 
-#: builtin/branch.c:813
+#: builtin/branch.c:836
 msgid "--column and --verbose are incompatible"
 msgstr ""
 
-#: builtin/branch.c:864
+#: builtin/branch.c:887
 #, c-format
 msgid "branch '%s' does not exist"
 msgstr ""
 
-#: builtin/branch.c:876
+#: builtin/branch.c:899
 #, c-format
 msgid "Branch '%s' has no upstream information"
 msgstr ""
 
-#: builtin/branch.c:891
+#: builtin/branch.c:914
 msgid "-a and -r options to 'git branch' do not make sense with a branch name"
 msgstr ""
 
-#: builtin/branch.c:894
+#: builtin/branch.c:917
 #, c-format
 msgid ""
 "The --set-upstream flag is deprecated and will be removed. Consider using --"
 "track or --set-upstream-to\n"
 msgstr ""
 
-#: builtin/branch.c:911
+#: builtin/branch.c:934
 #, c-format
 msgid ""
 "\n"
@@ -2367,12 +2404,12 @@ msgid ""
 "\n"
 msgstr ""
 
-#: builtin/branch.c:912
+#: builtin/branch.c:935
 #, c-format
 msgid "    git branch -d %s\n"
 msgstr ""
 
-#: builtin/branch.c:913
+#: builtin/branch.c:936
 #, c-format
 msgid "    git branch --set-upstream-to %s\n"
 msgstr ""
@@ -2561,11 +2598,6 @@ msgstr ""
 msgid "path '%s' is unmerged"
 msgstr ""
 
-#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586
-#: builtin/merge.c:811
-msgid "unable to write new index file"
-msgstr ""
-
 #: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
 msgstr ""
@@ -2594,7 +2626,7 @@ msgstr ""
 msgid "Switched to and reset branch '%s'\n"
 msgstr ""
 
-#: builtin/checkout.c:618
+#: builtin/checkout.c:618 builtin/checkout.c:955
 #, c-format
 msgid "Switched to a new branch '%s'\n"
 msgstr ""
@@ -2659,124 +2691,124 @@ msgstr ""
 msgid "reference is not a tree: %s"
 msgstr ""
 
-#: builtin/checkout.c:961
+#: builtin/checkout.c:964
 msgid "paths cannot be used with switching branches"
 msgstr ""
 
-#: builtin/checkout.c:964 builtin/checkout.c:968
+#: builtin/checkout.c:967 builtin/checkout.c:971
 #, c-format
 msgid "'%s' cannot be used with switching branches"
 msgstr ""
 
-#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
-#: builtin/checkout.c:983
+#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
+#: builtin/checkout.c:986
 #, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr ""
 
-#: builtin/checkout.c:988
+#: builtin/checkout.c:991
 #, c-format
 msgid "Cannot switch branch to a non-commit '%s'"
 msgstr ""
 
-#: builtin/checkout.c:1009 builtin/gc.c:177
+#: builtin/checkout.c:1012 builtin/gc.c:177
 msgid "suppress progress reporting"
 msgstr ""
 
-#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
 #: builtin/remote.c:169 builtin/remote.c:171
 msgid "branch"
 msgstr ""
 
-#: builtin/checkout.c:1011
+#: builtin/checkout.c:1014
 msgid "create and checkout a new branch"
 msgstr ""
 
-#: builtin/checkout.c:1013
+#: builtin/checkout.c:1016
 msgid "create/reset and checkout a branch"
 msgstr ""
 
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1017
 msgid "create reflog for new branch"
 msgstr ""
 
-#: builtin/checkout.c:1015
+#: builtin/checkout.c:1018
 msgid "detach the HEAD at named commit"
 msgstr ""
 
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1019
 msgid "set upstream info for new branch"
 msgstr ""
 
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1021
 msgid "new branch"
 msgstr ""
 
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1021
 msgid "new unparented branch"
 msgstr ""
 
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1022
 msgid "checkout our version for unmerged files"
 msgstr ""
 
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1024
 msgid "checkout their version for unmerged files"
 msgstr ""
 
-#: builtin/checkout.c:1023
+#: builtin/checkout.c:1026
 msgid "force checkout (throw away local modifications)"
 msgstr ""
 
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1027
 msgid "perform a 3-way merge with the new branch"
 msgstr ""
 
-#: builtin/checkout.c:1025 builtin/merge.c:215
+#: builtin/checkout.c:1028 builtin/merge.c:215
 msgid "update ignored files (default)"
 msgstr ""
 
-#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241
 msgid "style"
 msgstr ""
 
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1030
 msgid "conflict style (merge or diff3)"
 msgstr ""
 
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1033
 msgid "second guess 'git checkout no-such-branch'"
 msgstr ""
 
-#: builtin/checkout.c:1054
+#: builtin/checkout.c:1057
 msgid "-b, -B and --orphan are mutually exclusive"
 msgstr ""
 
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1074
 msgid "--track needs a branch name"
 msgstr ""
 
-#: builtin/checkout.c:1078
+#: builtin/checkout.c:1081
 msgid "Missing branch name; try -b"
 msgstr ""
 
-#: builtin/checkout.c:1113
+#: builtin/checkout.c:1116
 msgid "invalid path specification"
 msgstr ""
 
-#: builtin/checkout.c:1120
+#: builtin/checkout.c:1123
 #, c-format
 msgid ""
 "Cannot update paths and switch to branch '%s' at the same time.\n"
 "Did you intend to checkout '%s' which can not be resolved as commit?"
 msgstr ""
 
-#: builtin/checkout.c:1125
+#: builtin/checkout.c:1128
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr ""
 
-#: builtin/checkout.c:1129
+#: builtin/checkout.c:1132
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
@@ -2798,8 +2830,8 @@ msgstr ""
 msgid "remove whole directories"
 msgstr ""
 
-#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:803
-#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182
 msgid "pattern"
 msgstr ""
 
@@ -2920,7 +2952,7 @@ msgstr ""
 msgid "path to git-upload-pack on the remote"
 msgstr ""
 
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:748
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
 msgid "depth"
 msgstr ""
 
@@ -3134,93 +3166,93 @@ msgid ""
 "Otherwise, please use 'git reset'\n"
 msgstr ""
 
-#: builtin/commit.c:257
+#: builtin/commit.c:258
 msgid "failed to unpack HEAD tree object"
 msgstr ""
 
-#: builtin/commit.c:299
+#: builtin/commit.c:300
 msgid "unable to create temporary index"
 msgstr ""
 
-#: builtin/commit.c:305
+#: builtin/commit.c:306
 msgid "interactive add failed"
 msgstr ""
 
-#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
+#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
 msgid "unable to write new_index file"
 msgstr ""
 
-#: builtin/commit.c:390
+#: builtin/commit.c:391
 msgid "cannot do a partial commit during a merge."
 msgstr ""
 
-#: builtin/commit.c:392
+#: builtin/commit.c:393
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr ""
 
-#: builtin/commit.c:402
+#: builtin/commit.c:403
 msgid "cannot read the index"
 msgstr ""
 
-#: builtin/commit.c:422
+#: builtin/commit.c:423
 msgid "unable to write temporary index file"
 msgstr ""
 
-#: builtin/commit.c:509 builtin/commit.c:515
+#: builtin/commit.c:511 builtin/commit.c:517
 #, c-format
 msgid "invalid commit: %s"
 msgstr ""
 
-#: builtin/commit.c:538
+#: builtin/commit.c:540
 msgid "malformed --author parameter"
 msgstr ""
 
-#: builtin/commit.c:558
+#: builtin/commit.c:560
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr ""
 
-#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
+#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
 #, c-format
 msgid "could not lookup commit %s"
 msgstr ""
 
-#: builtin/commit.c:608 builtin/shortlog.c:296
+#: builtin/commit.c:610 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr ""
 
-#: builtin/commit.c:610
+#: builtin/commit.c:612
 msgid "could not read log from standard input"
 msgstr ""
 
-#: builtin/commit.c:614
+#: builtin/commit.c:616
 #, c-format
 msgid "could not read log file '%s'"
 msgstr ""
 
-#: builtin/commit.c:620
+#: builtin/commit.c:622
 msgid "commit has empty message"
 msgstr ""
 
-#: builtin/commit.c:636
+#: builtin/commit.c:638
 msgid "could not read MERGE_MSG"
 msgstr ""
 
-#: builtin/commit.c:640
+#: builtin/commit.c:642
 msgid "could not read SQUASH_MSG"
 msgstr ""
 
-#: builtin/commit.c:644
+#: builtin/commit.c:646
 #, c-format
 msgid "could not read '%s'"
 msgstr ""
 
-#: builtin/commit.c:705
+#: builtin/commit.c:707
 msgid "could not write commit template"
 msgstr ""
 
-#: builtin/commit.c:716
+#: builtin/commit.c:718
 #, c-format
 msgid ""
 "\n"
@@ -3230,7 +3262,7 @@ msgid ""
 "and try again.\n"
 msgstr ""
 
-#: builtin/commit.c:721
+#: builtin/commit.c:723
 #, c-format
 msgid ""
 "\n"
@@ -3240,356 +3272,364 @@ msgid ""
 "and try again.\n"
 msgstr ""
 
-#: builtin/commit.c:733
+#: builtin/commit.c:735
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
 msgstr ""
 
-#: builtin/commit.c:738
+#: builtin/commit.c:740
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be kept; you may remove them yourself if you want to.\n"
 "An empty message aborts the commit.\n"
 msgstr ""
 
-#: builtin/commit.c:751
+#: builtin/commit.c:753
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr ""
 
-#: builtin/commit.c:758
+#: builtin/commit.c:760
 #, c-format
 msgid "%sCommitter: %s"
 msgstr ""
 
-#: builtin/commit.c:778
+#: builtin/commit.c:780
 msgid "Cannot read index"
 msgstr ""
 
-#: builtin/commit.c:815
+#: builtin/commit.c:817
 msgid "Error building trees"
 msgstr ""
 
-#: builtin/commit.c:830 builtin/tag.c:361
+#: builtin/commit.c:832 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr ""
 
-#: builtin/commit.c:927
+#: builtin/commit.c:929
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr ""
 
-#: builtin/commit.c:942 builtin/commit.c:1142
+#: builtin/commit.c:944 builtin/commit.c:1148
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr ""
 
-#: builtin/commit.c:982
+#: builtin/commit.c:984
 msgid "Using both --reset-author and --author does not make sense"
 msgstr ""
 
-#: builtin/commit.c:993
+#: builtin/commit.c:995
 msgid "You have nothing to amend."
 msgstr ""
 
-#: builtin/commit.c:996
+#: builtin/commit.c:998
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr ""
 
-#: builtin/commit.c:998
+#: builtin/commit.c:1000
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr ""
 
-#: builtin/commit.c:1001
+#: builtin/commit.c:1003
 msgid "Options --squash and --fixup cannot be used together"
 msgstr ""
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:1013
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr ""
 
-#: builtin/commit.c:1013
+#: builtin/commit.c:1015
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr ""
 
-#: builtin/commit.c:1021
+#: builtin/commit.c:1023
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr ""
 
-#: builtin/commit.c:1038
+#: builtin/commit.c:1040
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 
-#: builtin/commit.c:1040
+#: builtin/commit.c:1042
 msgid "No paths with --include/--only does not make sense."
 msgstr ""
 
-#: builtin/commit.c:1042
+#: builtin/commit.c:1044
 msgid "Clever... amending the last one with dirty index."
 msgstr ""
 
-#: builtin/commit.c:1044
+#: builtin/commit.c:1046
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr ""
 
-#: builtin/commit.c:1054 builtin/tag.c:577
+#: builtin/commit.c:1056 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr ""
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1061
 msgid "Paths with -a does not make sense."
 msgstr ""
 
-#: builtin/commit.c:1156 builtin/commit.c:1384
+#: builtin/commit.c:1067 builtin/commit.c:1202
+msgid "--long and -z are incompatible"
+msgstr ""
+
+#: builtin/commit.c:1162 builtin/commit.c:1398
 msgid "show status concisely"
 msgstr ""
 
-#: builtin/commit.c:1158 builtin/commit.c:1386
+#: builtin/commit.c:1164 builtin/commit.c:1400
 msgid "show branch information"
 msgstr ""
 
-#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
+#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389
 msgid "machine-readable output"
 msgstr ""
 
-#: builtin/commit.c:1163 builtin/commit.c:1390
+#: builtin/commit.c:1169 builtin/commit.c:1404
+msgid "show status in long format (default)"
+msgstr ""
+
+#: builtin/commit.c:1172 builtin/commit.c:1407
 msgid "terminate entries with NUL"
 msgstr ""
 
-#: builtin/commit.c:1165 builtin/commit.c:1393 builtin/fast-export.c:636
+#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636
 #: builtin/fast-export.c:639 builtin/tag.c:461
 msgid "mode"
 msgstr ""
 
-#: builtin/commit.c:1166 builtin/commit.c:1393
+#: builtin/commit.c:1175 builtin/commit.c:1410
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 
-#: builtin/commit.c:1169
+#: builtin/commit.c:1178
 msgid "show ignored files"
 msgstr ""
 
-#: builtin/commit.c:1170 parse-options.h:151
+#: builtin/commit.c:1179 parse-options.h:151
 msgid "when"
 msgstr ""
 
-#: builtin/commit.c:1171
+#: builtin/commit.c:1180
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
 msgstr ""
 
-#: builtin/commit.c:1173
+#: builtin/commit.c:1182
 msgid "list untracked files in columns"
 msgstr ""
 
-#: builtin/commit.c:1242
+#: builtin/commit.c:1256
 msgid "couldn't look up newly created commit"
 msgstr ""
 
-#: builtin/commit.c:1244
+#: builtin/commit.c:1258
 msgid "could not parse newly created commit"
 msgstr ""
 
-#: builtin/commit.c:1285
+#: builtin/commit.c:1299
 msgid "detached HEAD"
 msgstr ""
 
-#: builtin/commit.c:1287
+#: builtin/commit.c:1301
 msgid " (root-commit)"
 msgstr ""
 
-#: builtin/commit.c:1354
+#: builtin/commit.c:1368
 msgid "suppress summary after successful commit"
 msgstr ""
 
-#: builtin/commit.c:1355
+#: builtin/commit.c:1369
 msgid "show diff in commit message template"
 msgstr ""
 
-#: builtin/commit.c:1357
+#: builtin/commit.c:1371
 msgid "Commit message options"
 msgstr ""
 
-#: builtin/commit.c:1358 builtin/tag.c:459
+#: builtin/commit.c:1372 builtin/tag.c:459
 msgid "read message from file"
 msgstr ""
 
-#: builtin/commit.c:1359
+#: builtin/commit.c:1373
 msgid "author"
 msgstr ""
 
-#: builtin/commit.c:1359
+#: builtin/commit.c:1373
 msgid "override author for commit"
 msgstr ""
 
-#: builtin/commit.c:1360 builtin/gc.c:178
+#: builtin/commit.c:1374 builtin/gc.c:178
 msgid "date"
 msgstr ""
 
-#: builtin/commit.c:1360
+#: builtin/commit.c:1374
 msgid "override date for commit"
 msgstr ""
 
-#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537
 #: builtin/notes.c:694 builtin/tag.c:457
 msgid "message"
 msgstr ""
 
-#: builtin/commit.c:1361
+#: builtin/commit.c:1375
 msgid "commit message"
 msgstr ""
 
-#: builtin/commit.c:1362
+#: builtin/commit.c:1376
 msgid "reuse and edit message from specified commit"
 msgstr ""
 
-#: builtin/commit.c:1363
+#: builtin/commit.c:1377
 msgid "reuse message from specified commit"
 msgstr ""
 
-#: builtin/commit.c:1364
+#: builtin/commit.c:1378
 msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
 
-#: builtin/commit.c:1365
+#: builtin/commit.c:1379
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 
-#: builtin/commit.c:1366
+#: builtin/commit.c:1380
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr ""
 
-#: builtin/commit.c:1367 builtin/log.c:1068 builtin/revert.c:109
+#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109
 msgid "add Signed-off-by:"
 msgstr ""
 
-#: builtin/commit.c:1368
+#: builtin/commit.c:1382
 msgid "use specified template file"
 msgstr ""
 
-#: builtin/commit.c:1369
+#: builtin/commit.c:1383
 msgid "force edit of commit"
 msgstr ""
 
-#: builtin/commit.c:1370
+#: builtin/commit.c:1384
 msgid "default"
 msgstr ""
 
-#: builtin/commit.c:1370 builtin/tag.c:462
+#: builtin/commit.c:1384 builtin/tag.c:462
 msgid "how to strip spaces and #comments from message"
 msgstr ""
 
-#: builtin/commit.c:1371
+#: builtin/commit.c:1385
 msgid "include status in commit message template"
 msgstr ""
 
-#: builtin/commit.c:1372 builtin/merge.c:213 builtin/tag.c:463
+#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463
 msgid "key id"
 msgstr ""
 
-#: builtin/commit.c:1373 builtin/merge.c:214
+#: builtin/commit.c:1387 builtin/merge.c:214
 msgid "GPG sign commit"
 msgstr ""
 
 #. end commit message options
-#: builtin/commit.c:1376
+#: builtin/commit.c:1390
 msgid "Commit contents options"
 msgstr ""
 
-#: builtin/commit.c:1377
+#: builtin/commit.c:1391
 msgid "commit all changed files"
 msgstr ""
 
-#: builtin/commit.c:1378
+#: builtin/commit.c:1392
 msgid "add specified files to index for commit"
 msgstr ""
 
-#: builtin/commit.c:1379
+#: builtin/commit.c:1393
 msgid "interactively add files"
 msgstr ""
 
-#: builtin/commit.c:1380
+#: builtin/commit.c:1394
 msgid "interactively add changes"
 msgstr ""
 
-#: builtin/commit.c:1381
+#: builtin/commit.c:1395
 msgid "commit only specified files"
 msgstr ""
 
-#: builtin/commit.c:1382
+#: builtin/commit.c:1396
 msgid "bypass pre-commit hook"
 msgstr ""
 
-#: builtin/commit.c:1383
+#: builtin/commit.c:1397
 msgid "show what would be committed"
 msgstr ""
 
-#: builtin/commit.c:1391
+#: builtin/commit.c:1408
 msgid "amend previous commit"
 msgstr ""
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1409
 msgid "bypass post-rewrite hook"
 msgstr ""
 
-#: builtin/commit.c:1397
+#: builtin/commit.c:1414
 msgid "ok to record an empty change"
 msgstr ""
 
-#: builtin/commit.c:1400
+#: builtin/commit.c:1417
 msgid "ok to record a change with an empty message"
 msgstr ""
 
-#: builtin/commit.c:1432
+#: builtin/commit.c:1449
 msgid "could not parse HEAD commit"
 msgstr ""
 
-#: builtin/commit.c:1470 builtin/merge.c:508
+#: builtin/commit.c:1487 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr ""
 
-#: builtin/commit.c:1477
+#: builtin/commit.c:1494
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr ""
 
-#: builtin/commit.c:1484
+#: builtin/commit.c:1501
 msgid "could not read MERGE_MODE"
 msgstr ""
 
-#: builtin/commit.c:1503
+#: builtin/commit.c:1520
 #, c-format
 msgid "could not read commit message: %s"
 msgstr ""
 
-#: builtin/commit.c:1517
+#: builtin/commit.c:1534
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr ""
 
-#: builtin/commit.c:1522
+#: builtin/commit.c:1539
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr ""
 
-#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
+#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857
 msgid "failed to write commit object"
 msgstr ""
 
-#: builtin/commit.c:1558
+#: builtin/commit.c:1575
 msgid "cannot lock HEAD ref"
 msgstr ""
 
-#: builtin/commit.c:1562
+#: builtin/commit.c:1579
 msgid "cannot update HEAD ref"
 msgstr ""
 
-#: builtin/commit.c:1573
+#: builtin/commit.c:1590
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -3600,115 +3640,115 @@ msgstr ""
 msgid "git config [options]"
 msgstr ""
 
-#: builtin/config.c:52
+#: builtin/config.c:51
 msgid "Config file location"
 msgstr ""
 
-#: builtin/config.c:53
+#: builtin/config.c:52
 msgid "use global config file"
 msgstr ""
 
-#: builtin/config.c:54
+#: builtin/config.c:53
 msgid "use system config file"
 msgstr ""
 
-#: builtin/config.c:55
+#: builtin/config.c:54
 msgid "use repository config file"
 msgstr ""
 
-#: builtin/config.c:56
+#: builtin/config.c:55
 msgid "use given config file"
 msgstr ""
 
-#: builtin/config.c:57
+#: builtin/config.c:56
 msgid "Action"
 msgstr ""
 
-#: builtin/config.c:58
+#: builtin/config.c:57
 msgid "get value: name [value-regex]"
 msgstr ""
 
-#: builtin/config.c:59
+#: builtin/config.c:58
 msgid "get all values: key [value-regex]"
 msgstr ""
 
-#: builtin/config.c:60
+#: builtin/config.c:59
 msgid "get values for regexp: name-regex [value-regex]"
 msgstr ""
 
-#: builtin/config.c:61
+#: builtin/config.c:60
 msgid "replace all matching variables: name value [value_regex]"
 msgstr ""
 
-#: builtin/config.c:62
+#: builtin/config.c:61
 msgid "add a new variable: name value"
 msgstr ""
 
-#: builtin/config.c:63
+#: builtin/config.c:62
 msgid "remove a variable: name [value-regex]"
 msgstr ""
 
-#: builtin/config.c:64
+#: builtin/config.c:63
 msgid "remove all matches: name [value-regex]"
 msgstr ""
 
-#: builtin/config.c:65
+#: builtin/config.c:64
 msgid "rename section: old-name new-name"
 msgstr ""
 
-#: builtin/config.c:66
+#: builtin/config.c:65
 msgid "remove a section: name"
 msgstr ""
 
-#: builtin/config.c:67
+#: builtin/config.c:66
 msgid "list all"
 msgstr ""
 
-#: builtin/config.c:68
+#: builtin/config.c:67
 msgid "open an editor"
 msgstr ""
 
-#: builtin/config.c:69 builtin/config.c:70
+#: builtin/config.c:68 builtin/config.c:69
 msgid "slot"
 msgstr ""
 
-#: builtin/config.c:69
+#: builtin/config.c:68
 msgid "find the color configured: [default]"
 msgstr ""
 
-#: builtin/config.c:70
+#: builtin/config.c:69
 msgid "find the color setting: [stdout-is-tty]"
 msgstr ""
 
-#: builtin/config.c:71
+#: builtin/config.c:70
 msgid "Type"
 msgstr ""
 
-#: builtin/config.c:72
+#: builtin/config.c:71
 msgid "value is \"true\" or \"false\""
 msgstr ""
 
-#: builtin/config.c:73
+#: builtin/config.c:72
 msgid "value is decimal number"
 msgstr ""
 
-#: builtin/config.c:74
+#: builtin/config.c:73
 msgid "value is --bool or --int"
 msgstr ""
 
-#: builtin/config.c:75
+#: builtin/config.c:74
 msgid "value is a path (file or directory name)"
 msgstr ""
 
-#: builtin/config.c:76
+#: builtin/config.c:75
 msgid "Other"
 msgstr ""
 
-#: builtin/config.c:77
+#: builtin/config.c:76
 msgid "terminate values with NUL byte"
 msgstr ""
 
-#: builtin/config.c:78
+#: builtin/config.c:77
 msgid "respect include directives on lookup"
 msgstr ""
 
@@ -3851,31 +3891,31 @@ msgstr ""
 msgid "'%s': not a regular file or symlink"
 msgstr ""
 
-#: builtin/diff.c:224
+#: builtin/diff.c:228
 #, c-format
 msgid "invalid option: %s"
 msgstr ""
 
-#: builtin/diff.c:301
+#: builtin/diff.c:305
 msgid "Not a git repository"
 msgstr ""
 
-#: builtin/diff.c:344
+#: builtin/diff.c:348
 #, c-format
 msgid "invalid object '%s' given."
 msgstr ""
 
-#: builtin/diff.c:349
+#: builtin/diff.c:353
 #, c-format
 msgid "more than %d trees given: '%s'"
 msgstr ""
 
-#: builtin/diff.c:359
+#: builtin/diff.c:363
 #, c-format
 msgid "more than two blobs given: '%s'"
 msgstr ""
 
-#: builtin/diff.c:367
+#: builtin/diff.c:371
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr ""
@@ -3988,7 +4028,7 @@ msgstr ""
 msgid "deepen history of shallow clone"
 msgstr ""
 
-#: builtin/fetch.c:85 builtin/log.c:1083
+#: builtin/fetch.c:85 builtin/log.c:1088
 msgid "dir"
 msgstr ""
 
@@ -4155,8 +4195,8 @@ msgstr ""
 msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
 msgstr ""
 
-#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:787
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
 #: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
 msgid "n"
 msgstr ""
@@ -4312,225 +4352,225 @@ msgstr ""
 msgid "grep: failed to create thread: %s"
 msgstr ""
 
-#: builtin/grep.c:455
+#: builtin/grep.c:365
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr ""
 
-#: builtin/grep.c:531 builtin/grep.c:565
+#: builtin/grep.c:443 builtin/grep.c:478
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr ""
 
-#: builtin/grep.c:579
+#: builtin/grep.c:493
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr ""
 
-#: builtin/grep.c:637
+#: builtin/grep.c:551
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr ""
 
-#: builtin/grep.c:654
+#: builtin/grep.c:568
 #, c-format
 msgid "cannot open '%s'"
 msgstr ""
 
-#: builtin/grep.c:729
+#: builtin/grep.c:643
 msgid "search in index instead of in the work tree"
 msgstr ""
 
-#: builtin/grep.c:731
+#: builtin/grep.c:645
 msgid "find in contents not managed by git"
 msgstr ""
 
-#: builtin/grep.c:733
+#: builtin/grep.c:647
 msgid "search in both tracked and untracked files"
 msgstr ""
 
-#: builtin/grep.c:735
+#: builtin/grep.c:649
 msgid "search also in ignored files"
 msgstr ""
 
-#: builtin/grep.c:738
+#: builtin/grep.c:652
 msgid "show non-matching lines"
 msgstr ""
 
-#: builtin/grep.c:740
+#: builtin/grep.c:654
 msgid "case insensitive matching"
 msgstr ""
 
-#: builtin/grep.c:742
+#: builtin/grep.c:656
 msgid "match patterns only at word boundaries"
 msgstr ""
 
-#: builtin/grep.c:744
+#: builtin/grep.c:658
 msgid "process binary files as text"
 msgstr ""
 
-#: builtin/grep.c:746
+#: builtin/grep.c:660
 msgid "don't match patterns in binary files"
 msgstr ""
 
-#: builtin/grep.c:749
+#: builtin/grep.c:663
 msgid "descend at most <depth> levels"
 msgstr ""
 
-#: builtin/grep.c:753
+#: builtin/grep.c:667
 msgid "use extended POSIX regular expressions"
 msgstr ""
 
-#: builtin/grep.c:756
+#: builtin/grep.c:670
 msgid "use basic POSIX regular expressions (default)"
 msgstr ""
 
-#: builtin/grep.c:759
+#: builtin/grep.c:673
 msgid "interpret patterns as fixed strings"
 msgstr ""
 
-#: builtin/grep.c:762
+#: builtin/grep.c:676
 msgid "use Perl-compatible regular expressions"
 msgstr ""
 
-#: builtin/grep.c:765
+#: builtin/grep.c:679
 msgid "show line numbers"
 msgstr ""
 
-#: builtin/grep.c:766
+#: builtin/grep.c:680
 msgid "don't show filenames"
 msgstr ""
 
-#: builtin/grep.c:767
+#: builtin/grep.c:681
 msgid "show filenames"
 msgstr ""
 
-#: builtin/grep.c:769
+#: builtin/grep.c:683
 msgid "show filenames relative to top directory"
 msgstr ""
 
-#: builtin/grep.c:771
+#: builtin/grep.c:685
 msgid "show only filenames instead of matching lines"
 msgstr ""
 
-#: builtin/grep.c:773
+#: builtin/grep.c:687
 msgid "synonym for --files-with-matches"
 msgstr ""
 
-#: builtin/grep.c:776
+#: builtin/grep.c:690
 msgid "show only the names of files without match"
 msgstr ""
 
-#: builtin/grep.c:778
+#: builtin/grep.c:692
 msgid "print NUL after filenames"
 msgstr ""
 
-#: builtin/grep.c:780
+#: builtin/grep.c:694
 msgid "show the number of matches instead of matching lines"
 msgstr ""
 
-#: builtin/grep.c:781
+#: builtin/grep.c:695
 msgid "highlight matches"
 msgstr ""
 
-#: builtin/grep.c:783
+#: builtin/grep.c:697
 msgid "print empty line between matches from different files"
 msgstr ""
 
-#: builtin/grep.c:785
+#: builtin/grep.c:699
 msgid "show filename only once above matches from same file"
 msgstr ""
 
-#: builtin/grep.c:788
+#: builtin/grep.c:702
 msgid "show <n> context lines before and after matches"
 msgstr ""
 
-#: builtin/grep.c:791
+#: builtin/grep.c:705
 msgid "show <n> context lines before matches"
 msgstr ""
 
-#: builtin/grep.c:793
+#: builtin/grep.c:707
 msgid "show <n> context lines after matches"
 msgstr ""
 
-#: builtin/grep.c:794
+#: builtin/grep.c:708
 msgid "shortcut for -C NUM"
 msgstr ""
 
-#: builtin/grep.c:797
+#: builtin/grep.c:711
 msgid "show a line with the function name before matches"
 msgstr ""
 
-#: builtin/grep.c:799
+#: builtin/grep.c:713
 msgid "show the surrounding function"
 msgstr ""
 
-#: builtin/grep.c:802
+#: builtin/grep.c:716
 msgid "read patterns from file"
 msgstr ""
 
-#: builtin/grep.c:804
+#: builtin/grep.c:718
 msgid "match <pattern>"
 msgstr ""
 
-#: builtin/grep.c:806
+#: builtin/grep.c:720
 msgid "combine patterns specified with -e"
 msgstr ""
 
-#: builtin/grep.c:818
+#: builtin/grep.c:732
 msgid "indicate hit with exit status without output"
 msgstr ""
 
-#: builtin/grep.c:820
+#: builtin/grep.c:734
 msgid "show only matches from files that match all patterns"
 msgstr ""
 
-#: builtin/grep.c:822
+#: builtin/grep.c:736
 msgid "show parse tree for grep expression"
 msgstr ""
 
-#: builtin/grep.c:826
+#: builtin/grep.c:740
 msgid "pager"
 msgstr ""
 
-#: builtin/grep.c:826
+#: builtin/grep.c:740
 msgid "show matching files in the pager"
 msgstr ""
 
-#: builtin/grep.c:829
+#: builtin/grep.c:743
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr ""
 
-#: builtin/grep.c:830 builtin/show-ref.c:201
+#: builtin/grep.c:744 builtin/show-ref.c:184
 msgid "show usage"
 msgstr ""
 
-#: builtin/grep.c:921
+#: builtin/grep.c:811
 msgid "no pattern given."
 msgstr ""
 
-#: builtin/grep.c:935
+#: builtin/grep.c:825
 #, c-format
 msgid "bad object %s"
 msgstr ""
 
-#: builtin/grep.c:976
+#: builtin/grep.c:866
 msgid "--open-files-in-pager only works on the worktree"
 msgstr ""
 
-#: builtin/grep.c:999
+#: builtin/grep.c:889
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr ""
 
-#: builtin/grep.c:1004
+#: builtin/grep.c:894
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr ""
 
-#: builtin/grep.c:1007
+#: builtin/grep.c:897
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr ""
 
-#: builtin/grep.c:1015
+#: builtin/grep.c:905
 msgid "both --cached and trees are given."
 msgstr ""
 
@@ -5114,219 +5154,219 @@ msgstr ""
 msgid "Final output: %d %s\n"
 msgstr ""
 
-#: builtin/log.c:403 builtin/log.c:494
+#: builtin/log.c:405 builtin/log.c:497
 #, c-format
 msgid "Could not read object %s"
 msgstr ""
 
-#: builtin/log.c:518
+#: builtin/log.c:521
 #, c-format
 msgid "Unknown type: %d"
 msgstr ""
 
-#: builtin/log.c:608
+#: builtin/log.c:613
 msgid "format.headers without value"
 msgstr ""
 
-#: builtin/log.c:682
+#: builtin/log.c:687
 msgid "name of output directory is too long"
 msgstr ""
 
-#: builtin/log.c:693
+#: builtin/log.c:698
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr ""
 
-#: builtin/log.c:707
+#: builtin/log.c:712
 msgid "Need exactly one range."
 msgstr ""
 
-#: builtin/log.c:715
+#: builtin/log.c:720
 msgid "Not a range."
 msgstr ""
 
-#: builtin/log.c:789
+#: builtin/log.c:794
 msgid "Cover letter needs email format"
 msgstr ""
 
-#: builtin/log.c:862
+#: builtin/log.c:867
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr ""
 
-#: builtin/log.c:890
+#: builtin/log.c:895
 msgid "git format-patch [options] [<since> | <revision range>]"
 msgstr ""
 
-#: builtin/log.c:935
+#: builtin/log.c:940
 msgid "Two output directories?"
 msgstr ""
 
-#: builtin/log.c:1063
+#: builtin/log.c:1068
 msgid "use [PATCH n/m] even with a single patch"
 msgstr ""
 
-#: builtin/log.c:1066
+#: builtin/log.c:1071
 msgid "use [PATCH] even with multiple patches"
 msgstr ""
 
-#: builtin/log.c:1070
+#: builtin/log.c:1075
 msgid "print patches to standard out"
 msgstr ""
 
-#: builtin/log.c:1072
+#: builtin/log.c:1077
 msgid "generate a cover letter"
 msgstr ""
 
-#: builtin/log.c:1074
+#: builtin/log.c:1079
 msgid "use simple number sequence for output file names"
 msgstr ""
 
-#: builtin/log.c:1075
+#: builtin/log.c:1080
 msgid "sfx"
 msgstr ""
 
-#: builtin/log.c:1076
+#: builtin/log.c:1081
 msgid "use <sfx> instead of '.patch'"
 msgstr ""
 
-#: builtin/log.c:1078
+#: builtin/log.c:1083
 msgid "start numbering patches at <n> instead of 1"
 msgstr ""
 
-#: builtin/log.c:1080
+#: builtin/log.c:1085
 msgid "Use [<prefix>] instead of [PATCH]"
 msgstr ""
 
-#: builtin/log.c:1083
+#: builtin/log.c:1088
 msgid "store resulting files in <dir>"
 msgstr ""
 
-#: builtin/log.c:1086
+#: builtin/log.c:1091
 msgid "don't strip/add [PATCH]"
 msgstr ""
 
-#: builtin/log.c:1089
+#: builtin/log.c:1094
 msgid "don't output binary diffs"
 msgstr ""
 
-#: builtin/log.c:1091
+#: builtin/log.c:1096
 msgid "don't include a patch matching a commit upstream"
 msgstr ""
 
-#: builtin/log.c:1093
+#: builtin/log.c:1098
 msgid "show patch format instead of default (patch + stat)"
 msgstr ""
 
-#: builtin/log.c:1095
+#: builtin/log.c:1100
 msgid "Messaging"
 msgstr ""
 
-#: builtin/log.c:1096
+#: builtin/log.c:1101
 msgid "header"
 msgstr ""
 
-#: builtin/log.c:1097
+#: builtin/log.c:1102
 msgid "add email header"
 msgstr ""
 
-#: builtin/log.c:1098 builtin/log.c:1100
+#: builtin/log.c:1103 builtin/log.c:1105
 msgid "email"
 msgstr ""
 
-#: builtin/log.c:1098
+#: builtin/log.c:1103
 msgid "add To: header"
 msgstr ""
 
-#: builtin/log.c:1100
+#: builtin/log.c:1105
 msgid "add Cc: header"
 msgstr ""
 
-#: builtin/log.c:1102
+#: builtin/log.c:1107
 msgid "message-id"
 msgstr ""
 
-#: builtin/log.c:1103
+#: builtin/log.c:1108
 msgid "make first mail a reply to <message-id>"
 msgstr ""
 
-#: builtin/log.c:1104 builtin/log.c:1107
+#: builtin/log.c:1109 builtin/log.c:1112
 msgid "boundary"
 msgstr ""
 
-#: builtin/log.c:1105
+#: builtin/log.c:1110
 msgid "attach the patch"
 msgstr ""
 
-#: builtin/log.c:1108
+#: builtin/log.c:1113
 msgid "inline the patch"
 msgstr ""
 
-#: builtin/log.c:1112
+#: builtin/log.c:1117
 msgid "enable message threading, styles: shallow, deep"
 msgstr ""
 
-#: builtin/log.c:1114
+#: builtin/log.c:1119
 msgid "signature"
 msgstr ""
 
-#: builtin/log.c:1115
+#: builtin/log.c:1120
 msgid "add a signature"
 msgstr ""
 
-#: builtin/log.c:1117
+#: builtin/log.c:1122
 msgid "don't print the patch filenames"
 msgstr ""
 
-#: builtin/log.c:1157
+#: builtin/log.c:1163
 #, c-format
 msgid "bogus committer info %s"
 msgstr ""
 
-#: builtin/log.c:1202
+#: builtin/log.c:1208
 msgid "-n and -k are mutually exclusive."
 msgstr ""
 
-#: builtin/log.c:1204
+#: builtin/log.c:1210
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr ""
 
-#: builtin/log.c:1212
+#: builtin/log.c:1218
 msgid "--name-only does not make sense"
 msgstr ""
 
-#: builtin/log.c:1214
+#: builtin/log.c:1220
 msgid "--name-status does not make sense"
 msgstr ""
 
-#: builtin/log.c:1216
+#: builtin/log.c:1222
 msgid "--check does not make sense"
 msgstr ""
 
-#: builtin/log.c:1239
+#: builtin/log.c:1245
 msgid "standard output, or directory, which one?"
 msgstr ""
 
-#: builtin/log.c:1241
+#: builtin/log.c:1247
 #, c-format
 msgid "Could not create directory '%s'"
 msgstr ""
 
-#: builtin/log.c:1394
+#: builtin/log.c:1400
 msgid "Failed to create output files"
 msgstr ""
 
-#: builtin/log.c:1443
+#: builtin/log.c:1449
 msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
 msgstr ""
 
-#: builtin/log.c:1498
+#: builtin/log.c:1504
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr ""
 
-#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
+#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531
 #, c-format
 msgid "Unknown commit %s"
 msgstr ""
@@ -5603,35 +5643,31 @@ msgstr ""
 msgid "git write-tree failed to write a tree"
 msgstr ""
 
-#: builtin/merge.c:678
-msgid "failed to read the cache"
-msgstr ""
-
-#: builtin/merge.c:709
+#: builtin/merge.c:656
 msgid "Not handling anything other than two heads merge."
 msgstr ""
 
-#: builtin/merge.c:723
+#: builtin/merge.c:670
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr ""
 
-#: builtin/merge.c:737
+#: builtin/merge.c:684
 #, c-format
 msgid "unable to write %s"
 msgstr ""
 
-#: builtin/merge.c:876
+#: builtin/merge.c:773
 #, c-format
 msgid "Could not read from '%s'"
 msgstr ""
 
-#: builtin/merge.c:885
+#: builtin/merge.c:782
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
 
-#: builtin/merge.c:891
+#: builtin/merge.c:788
 msgid ""
 "Please enter a commit message to explain why this merge is necessary,\n"
 "especially if it merges an updated upstream into a topic branch.\n"
@@ -5640,140 +5676,140 @@ msgid ""
 "the commit.\n"
 msgstr ""
 
-#: builtin/merge.c:915
+#: builtin/merge.c:812
 msgid "Empty commit message."
 msgstr ""
 
-#: builtin/merge.c:927
+#: builtin/merge.c:824
 #, c-format
 msgid "Wonderful.\n"
 msgstr ""
 
-#: builtin/merge.c:992
+#: builtin/merge.c:889
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
 
-#: builtin/merge.c:1008
+#: builtin/merge.c:905
 #, c-format
 msgid "'%s' is not a commit"
 msgstr ""
 
-#: builtin/merge.c:1049
+#: builtin/merge.c:946
 msgid "No current branch."
 msgstr ""
 
-#: builtin/merge.c:1051
+#: builtin/merge.c:948
 msgid "No remote for the current branch."
 msgstr ""
 
-#: builtin/merge.c:1053
+#: builtin/merge.c:950
 msgid "No default upstream defined for the current branch."
 msgstr ""
 
-#: builtin/merge.c:1058
+#: builtin/merge.c:955
 #, c-format
 msgid "No remote tracking branch for %s from %s"
 msgstr ""
 
-#: builtin/merge.c:1145 builtin/merge.c:1302
+#: builtin/merge.c:1042 builtin/merge.c:1199
 #, c-format
 msgid "%s - not something we can merge"
 msgstr ""
 
-#: builtin/merge.c:1213
+#: builtin/merge.c:1110
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr ""
 
-#: builtin/merge.c:1229 git-pull.sh:31
+#: builtin/merge.c:1126 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
 msgstr ""
 
-#: builtin/merge.c:1232 git-pull.sh:34
+#: builtin/merge.c:1129 git-pull.sh:34
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr ""
 
-#: builtin/merge.c:1236
+#: builtin/merge.c:1133
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
 msgstr ""
 
-#: builtin/merge.c:1239
+#: builtin/merge.c:1136
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr ""
 
-#: builtin/merge.c:1248
+#: builtin/merge.c:1145
 msgid "You cannot combine --squash with --no-ff."
 msgstr ""
 
-#: builtin/merge.c:1253
+#: builtin/merge.c:1150
 msgid "You cannot combine --no-ff with --ff-only."
 msgstr ""
 
-#: builtin/merge.c:1260
+#: builtin/merge.c:1157
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr ""
 
-#: builtin/merge.c:1292
+#: builtin/merge.c:1189
 msgid "Can merge only exactly one commit into empty head"
 msgstr ""
 
-#: builtin/merge.c:1295
+#: builtin/merge.c:1192
 msgid "Squash commit into empty head not supported yet"
 msgstr ""
 
-#: builtin/merge.c:1297
+#: builtin/merge.c:1194
 msgid "Non-fast-forward commit does not make sense into an empty head"
 msgstr ""
 
-#: builtin/merge.c:1412
+#: builtin/merge.c:1309
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr ""
 
-#: builtin/merge.c:1450
+#: builtin/merge.c:1348
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr ""
 
-#: builtin/merge.c:1457
+#: builtin/merge.c:1355
 #, c-format
 msgid "Nope.\n"
 msgstr ""
 
-#: builtin/merge.c:1489
+#: builtin/merge.c:1387
 msgid "Not possible to fast-forward, aborting."
 msgstr ""
 
-#: builtin/merge.c:1512 builtin/merge.c:1591
+#: builtin/merge.c:1410 builtin/merge.c:1489
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr ""
 
-#: builtin/merge.c:1516
+#: builtin/merge.c:1414
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr ""
 
-#: builtin/merge.c:1582
+#: builtin/merge.c:1480
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr ""
 
-#: builtin/merge.c:1584
+#: builtin/merge.c:1482
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr ""
 
-#: builtin/merge.c:1593
+#: builtin/merge.c:1491
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
 msgstr ""
 
-#: builtin/merge.c:1605
+#: builtin/merge.c:1503
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
@@ -6323,143 +6359,143 @@ msgstr ""
 msgid "deflate error (%d)"
 msgstr ""
 
-#: builtin/pack-objects.c:2398
+#: builtin/pack-objects.c:2397
 #, c-format
 msgid "unsupported index version %s"
 msgstr ""
 
-#: builtin/pack-objects.c:2402
+#: builtin/pack-objects.c:2401
 #, c-format
 msgid "bad index version '%s'"
 msgstr ""
 
-#: builtin/pack-objects.c:2425
+#: builtin/pack-objects.c:2424
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr ""
 
-#: builtin/pack-objects.c:2429
+#: builtin/pack-objects.c:2428
 #, c-format
 msgid "unable to parse value '%s' for option %s"
 msgstr ""
 
-#: builtin/pack-objects.c:2448
+#: builtin/pack-objects.c:2447
 msgid "do not show progress meter"
 msgstr ""
 
-#: builtin/pack-objects.c:2450
+#: builtin/pack-objects.c:2449
 msgid "show progress meter"
 msgstr ""
 
-#: builtin/pack-objects.c:2452
+#: builtin/pack-objects.c:2451
 msgid "show progress meter during object writing phase"
 msgstr ""
 
-#: builtin/pack-objects.c:2455
+#: builtin/pack-objects.c:2454
 msgid "similar to --all-progress when progress meter is shown"
 msgstr ""
 
-#: builtin/pack-objects.c:2456
+#: builtin/pack-objects.c:2455
 msgid "version[,offset]"
 msgstr ""
 
-#: builtin/pack-objects.c:2457
+#: builtin/pack-objects.c:2456
 msgid "write the pack index file in the specified idx format version"
 msgstr ""
 
-#: builtin/pack-objects.c:2460
+#: builtin/pack-objects.c:2459
 msgid "maximum size of each output pack file"
 msgstr ""
 
-#: builtin/pack-objects.c:2462
+#: builtin/pack-objects.c:2461
 msgid "ignore borrowed objects from alternate object store"
 msgstr ""
 
-#: builtin/pack-objects.c:2464
+#: builtin/pack-objects.c:2463
 msgid "ignore packed objects"
 msgstr ""
 
-#: builtin/pack-objects.c:2466
+#: builtin/pack-objects.c:2465
 msgid "limit pack window by objects"
 msgstr ""
 
-#: builtin/pack-objects.c:2468
+#: builtin/pack-objects.c:2467
 msgid "limit pack window by memory in addition to object limit"
 msgstr ""
 
-#: builtin/pack-objects.c:2470
+#: builtin/pack-objects.c:2469
 msgid "maximum length of delta chain allowed in the resulting pack"
 msgstr ""
 
-#: builtin/pack-objects.c:2472
+#: builtin/pack-objects.c:2471
 msgid "reuse existing deltas"
 msgstr ""
 
-#: builtin/pack-objects.c:2474
+#: builtin/pack-objects.c:2473
 msgid "reuse existing objects"
 msgstr ""
 
-#: builtin/pack-objects.c:2476
+#: builtin/pack-objects.c:2475
 msgid "use OFS_DELTA objects"
 msgstr ""
 
-#: builtin/pack-objects.c:2478
+#: builtin/pack-objects.c:2477
 msgid "use threads when searching for best delta matches"
 msgstr ""
 
-#: builtin/pack-objects.c:2480
+#: builtin/pack-objects.c:2479
 msgid "do not create an empty pack output"
 msgstr ""
 
-#: builtin/pack-objects.c:2482
+#: builtin/pack-objects.c:2481
 msgid "read revision arguments from standard input"
 msgstr ""
 
-#: builtin/pack-objects.c:2484
+#: builtin/pack-objects.c:2483
 msgid "limit the objects to those that are not yet packed"
 msgstr ""
 
-#: builtin/pack-objects.c:2487
+#: builtin/pack-objects.c:2486
 msgid "include objects reachable from any reference"
 msgstr ""
 
-#: builtin/pack-objects.c:2490
+#: builtin/pack-objects.c:2489
 msgid "include objects referred by reflog entries"
 msgstr ""
 
-#: builtin/pack-objects.c:2493
+#: builtin/pack-objects.c:2492
 msgid "output pack to stdout"
 msgstr ""
 
-#: builtin/pack-objects.c:2495
+#: builtin/pack-objects.c:2494
 msgid "include tag objects that refer to objects to be packed"
 msgstr ""
 
-#: builtin/pack-objects.c:2497
+#: builtin/pack-objects.c:2496
 msgid "keep unreachable objects"
 msgstr ""
 
-#: builtin/pack-objects.c:2498 parse-options.h:141
+#: builtin/pack-objects.c:2497 parse-options.h:141
 msgid "time"
 msgstr ""
 
-#: builtin/pack-objects.c:2499
+#: builtin/pack-objects.c:2498
 msgid "unpack unreachable objects newer than <time>"
 msgstr ""
 
-#: builtin/pack-objects.c:2502
+#: builtin/pack-objects.c:2501
 msgid "create thin packs"
 msgstr ""
 
-#: builtin/pack-objects.c:2504
+#: builtin/pack-objects.c:2503
 msgid "ignore packs that have companion .keep file"
 msgstr ""
 
-#: builtin/pack-objects.c:2506
+#: builtin/pack-objects.c:2505
 msgid "pack compression level"
 msgstr ""
 
-#: builtin/pack-objects.c:2508
+#: builtin/pack-objects.c:2507
 msgid "do not hide commits by grafts"
 msgstr ""
 
@@ -6800,7 +6836,7 @@ msgstr ""
 msgid "git remote remove <name>"
 msgstr ""
 
-#: builtin/remote.c:15
+#: builtin/remote.c:15 builtin/remote.c:42
 msgid "git remote set-head <name> (-a | -d | <branch>)"
 msgstr ""
 
@@ -6837,10 +6873,6 @@ msgstr ""
 msgid "git remote add [<options>] <name> <url>"
 msgstr ""
 
-#: builtin/remote.c:42
-msgid "git remote set-head <name> (-a | -d | <branch>])"
-msgstr ""
-
 #: builtin/remote.c:47
 msgid "git remote set-branches <name> <branch>..."
 msgstr ""
@@ -7280,15 +7312,15 @@ msgstr ""
 msgid "git replace -l [<pattern>]"
 msgstr ""
 
-#: builtin/replace.c:118
+#: builtin/replace.c:121
 msgid "list replace refs"
 msgstr ""
 
-#: builtin/replace.c:119
+#: builtin/replace.c:122
 msgid "delete replace refs"
 msgstr ""
 
-#: builtin/replace.c:120
+#: builtin/replace.c:123
 msgid "replace the ref if it exists"
 msgstr ""
 
@@ -7526,57 +7558,64 @@ msgstr ""
 msgid "cherry-pick failed"
 msgstr ""
 
-#: builtin/rm.c:14
+#: builtin/rm.c:15
 msgid "git rm [options] [--] <file>..."
 msgstr ""
 
-#: builtin/rm.c:109
+#: builtin/rm.c:64 builtin/rm.c:186
+#, c-format
+msgid ""
+"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+
+#: builtin/rm.c:174
 #, c-format
 msgid ""
 "'%s' has staged content different from both the file and the HEAD\n"
 "(use -f to force removal)"
 msgstr ""
 
-#: builtin/rm.c:115
+#: builtin/rm.c:180
 #, c-format
 msgid ""
 "'%s' has changes staged in the index\n"
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 
-#: builtin/rm.c:119
+#: builtin/rm.c:191
 #, c-format
 msgid ""
 "'%s' has local modifications\n"
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 
-#: builtin/rm.c:134
+#: builtin/rm.c:207
 msgid "do not list removed files"
 msgstr ""
 
-#: builtin/rm.c:135
+#: builtin/rm.c:208
 msgid "only remove from the index"
 msgstr ""
 
-#: builtin/rm.c:136
+#: builtin/rm.c:209
 msgid "override the up-to-date check"
 msgstr ""
 
-#: builtin/rm.c:137
+#: builtin/rm.c:210
 msgid "allow recursive removal"
 msgstr ""
 
-#: builtin/rm.c:139
+#: builtin/rm.c:212
 msgid "exit with a zero status even if nothing matched"
 msgstr ""
 
-#: builtin/rm.c:194
+#: builtin/rm.c:283
 #, c-format
 msgid "not removing '%s' recursively without -r"
 msgstr ""
 
-#: builtin/rm.c:230
+#: builtin/rm.c:322
 #, c-format
 msgid "git rm: unable to remove %s"
 msgstr ""
@@ -7696,35 +7735,35 @@ msgstr ""
 msgid "git show-ref --exclude-existing[=pattern] < ref-list"
 msgstr ""
 
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:165
 msgid "only show tags (can be combined with heads)"
 msgstr ""
 
-#: builtin/show-ref.c:183
+#: builtin/show-ref.c:166
 msgid "only show heads (can be combined with tags)"
 msgstr ""
 
-#: builtin/show-ref.c:184
+#: builtin/show-ref.c:167
 msgid "stricter reference checking, requires exact ref path"
 msgstr ""
 
-#: builtin/show-ref.c:187 builtin/show-ref.c:189
+#: builtin/show-ref.c:170 builtin/show-ref.c:172
 msgid "show the HEAD reference"
 msgstr ""
 
-#: builtin/show-ref.c:191
+#: builtin/show-ref.c:174
 msgid "dereference tags into object IDs"
 msgstr ""
 
-#: builtin/show-ref.c:193
+#: builtin/show-ref.c:176
 msgid "only show SHA1 hash using <n> digits"
 msgstr ""
 
-#: builtin/show-ref.c:197
+#: builtin/show-ref.c:180
 msgid "do not print results to stdout (useful with --verify)"
 msgstr ""
 
-#: builtin/show-ref.c:199
+#: builtin/show-ref.c:182
 msgid "show refs from stdin that aren't in local repository"
 msgstr ""
 
@@ -7732,19 +7771,27 @@ msgstr ""
 msgid "git symbolic-ref [options] name [ref]"
 msgstr ""
 
-#: builtin/symbolic-ref.c:38
+#: builtin/symbolic-ref.c:8
+msgid "git symbolic-ref -d [-q] name"
+msgstr ""
+
+#: builtin/symbolic-ref.c:40
 msgid "suppress error message for non-symbolic (detached) refs"
 msgstr ""
 
-#: builtin/symbolic-ref.c:39
+#: builtin/symbolic-ref.c:41
+msgid "delete symbolic ref"
+msgstr ""
+
+#: builtin/symbolic-ref.c:42
 msgid "shorten ref output"
 msgstr ""
 
-#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
 msgid "reason"
 msgstr ""
 
-#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
 msgid "reason of the update"
 msgstr ""
 
@@ -7954,111 +8001,111 @@ msgstr ""
 msgid "git update-index [options] [--] [<file>...]"
 msgstr ""
 
-#: builtin/update-index.c:717
+#: builtin/update-index.c:718
 msgid "continue refresh even when index needs update"
 msgstr ""
 
-#: builtin/update-index.c:720
+#: builtin/update-index.c:721
 msgid "refresh: ignore submodules"
 msgstr ""
 
-#: builtin/update-index.c:723
+#: builtin/update-index.c:724
 msgid "do not ignore new files"
 msgstr ""
 
-#: builtin/update-index.c:725
+#: builtin/update-index.c:726
 msgid "let files replace directories and vice-versa"
 msgstr ""
 
-#: builtin/update-index.c:727
+#: builtin/update-index.c:728
 msgid "notice files missing from worktree"
 msgstr ""
 
-#: builtin/update-index.c:729
+#: builtin/update-index.c:730
 msgid "refresh even if index contains unmerged entries"
 msgstr ""
 
-#: builtin/update-index.c:732
+#: builtin/update-index.c:733
 msgid "refresh stat information"
 msgstr ""
 
-#: builtin/update-index.c:736
+#: builtin/update-index.c:737
 msgid "like --refresh, but ignore assume-unchanged setting"
 msgstr ""
 
-#: builtin/update-index.c:740
+#: builtin/update-index.c:741
 msgid "<mode> <object> <path>"
 msgstr ""
 
-#: builtin/update-index.c:741
+#: builtin/update-index.c:742
 msgid "add the specified entry to the index"
 msgstr ""
 
-#: builtin/update-index.c:745
+#: builtin/update-index.c:746
 msgid "(+/-)x"
 msgstr ""
 
-#: builtin/update-index.c:746
+#: builtin/update-index.c:747
 msgid "override the executable bit of the listed files"
 msgstr ""
 
-#: builtin/update-index.c:750
+#: builtin/update-index.c:751
 msgid "mark files as \"not changing\""
 msgstr ""
 
-#: builtin/update-index.c:753
+#: builtin/update-index.c:754
 msgid "clear assumed-unchanged bit"
 msgstr ""
 
-#: builtin/update-index.c:756
+#: builtin/update-index.c:757
 msgid "mark files as \"index-only\""
 msgstr ""
 
-#: builtin/update-index.c:759
+#: builtin/update-index.c:760
 msgid "clear skip-worktree bit"
 msgstr ""
 
-#: builtin/update-index.c:762
+#: builtin/update-index.c:763
 msgid "add to index only; do not add content to object database"
 msgstr ""
 
-#: builtin/update-index.c:764
+#: builtin/update-index.c:765
 msgid "remove named paths even if present in worktree"
 msgstr ""
 
-#: builtin/update-index.c:766
+#: builtin/update-index.c:767
 msgid "with --stdin: input lines are terminated by null bytes"
 msgstr ""
 
-#: builtin/update-index.c:768
+#: builtin/update-index.c:769
 msgid "read list of paths to be updated from standard input"
 msgstr ""
 
-#: builtin/update-index.c:772
+#: builtin/update-index.c:773
 msgid "add entries from standard input to the index"
 msgstr ""
 
-#: builtin/update-index.c:776
+#: builtin/update-index.c:777
 msgid "repopulate stages #2 and #3 for the listed paths"
 msgstr ""
 
-#: builtin/update-index.c:780
+#: builtin/update-index.c:781
 msgid "only update entries that differ from HEAD"
 msgstr ""
 
-#: builtin/update-index.c:784
+#: builtin/update-index.c:785
 msgid "ignore files missing from worktree"
 msgstr ""
 
-#: builtin/update-index.c:787
+#: builtin/update-index.c:788
 msgid "report actions to standard output"
 msgstr ""
 
-#: builtin/update-index.c:789
+#: builtin/update-index.c:790
 msgid "(for porcelains) forget saved unresolved conflicts"
 msgstr ""
 
-#: builtin/update-index.c:793
+#: builtin/update-index.c:794
 msgid "write index in this format"
 msgstr ""
 
@@ -8535,7 +8582,7 @@ msgstr ""
 #. The working tree and the index file is still based on the
 #. $orig_head commit, but we are merging into $curr_head.
 #. First update the working tree to match $curr_head.
-#: git-pull.sh:228
+#: git-pull.sh:229
 #, sh-format
 msgid ""
 "Warning: fetch updated the current branch head.\n"
@@ -8543,11 +8590,11 @@ msgid ""
 "Warning: commit $orig_head."
 msgstr ""
 
-#: git-pull.sh:253
+#: git-pull.sh:254
 msgid "Cannot merge multiple branches into empty head"
 msgstr ""
 
-#: git-pull.sh:257
+#: git-pull.sh:258
 msgid "Cannot rebase onto multiple branches"
 msgstr ""
 
@@ -8788,12 +8835,12 @@ msgstr ""
 msgid "(To restore them type \"git stash apply\")"
 msgstr ""
 
-#: git-submodule.sh:88
+#: git-submodule.sh:89
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
 msgstr ""
 
-#: git-submodule.sh:167
+#: git-submodule.sh:168
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
@@ -8808,17 +8855,17 @@ msgstr ""
 msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
 msgstr ""
 
-#: git-submodule.sh:312
+#: git-submodule.sh:316
 #, sh-format
 msgid "repo URL: '$repo' must be absolute or begin with ./|../"
 msgstr ""
 
-#: git-submodule.sh:329
+#: git-submodule.sh:333
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr ""
 
-#: git-submodule.sh:333
+#: git-submodule.sh:337
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -8826,151 +8873,180 @@ msgid ""
 "Use -f if you really want to add it."
 msgstr ""
 
-#: git-submodule.sh:344
+#: git-submodule.sh:355
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
 msgstr ""
 
-#: git-submodule.sh:346
+#: git-submodule.sh:357
 #, sh-format
 msgid "'$sm_path' already exists and is not a valid git repo"
 msgstr ""
 
-#: git-submodule.sh:360
+#: git-submodule.sh:365
+#, sh-format
+msgid "A git directory for '$sm_name' is found locally with remote(s):"
+msgstr ""
+
+#: git-submodule.sh:367
+#, sh-format
+msgid ""
+"If you want to reuse this local git directory instead of cloning again from"
+msgstr ""
+
+#: git-submodule.sh:369
+#, sh-format
+msgid ""
+"use the '--force' option. If the local git directory is not the correct repo"
+msgstr ""
+
+#: git-submodule.sh:370
+#, sh-format
+msgid ""
+"or you are unsure what this means choose another name with the '--name' "
+"option."
+msgstr ""
+
+#: git-submodule.sh:372
+#, sh-format
+msgid "Reactivating local git directory for submodule '$sm_name'."
+msgstr ""
+
+#: git-submodule.sh:384
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:365
+#: git-submodule.sh:389
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:370
+#: git-submodule.sh:394
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:413
+#: git-submodule.sh:437
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:427
+#: git-submodule.sh:451
 #, sh-format
 msgid "Stopping at '$sm_path'; script returned non-zero status."
 msgstr ""
 
-#: git-submodule.sh:471
+#: git-submodule.sh:495
 #, sh-format
 msgid "No url found for submodule path '$sm_path' in .gitmodules"
 msgstr ""
 
-#: git-submodule.sh:480
+#: git-submodule.sh:504
 #, sh-format
 msgid "Failed to register url for submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:482
+#: git-submodule.sh:506
 #, sh-format
 msgid "Submodule '$name' ($url) registered for path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:490
+#: git-submodule.sh:514
 #, sh-format
 msgid "Failed to register update mode for submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:590
+#: git-submodule.sh:614
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
 "Maybe you want to use 'update --init'?"
 msgstr ""
 
-#: git-submodule.sh:603
+#: git-submodule.sh:627
 #, sh-format
 msgid "Unable to find current revision in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:622
+#: git-submodule.sh:646
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:636
+#: git-submodule.sh:660
 #, sh-format
 msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:637
+#: git-submodule.sh:661
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr ""
 
-#: git-submodule.sh:642
+#: git-submodule.sh:666
 #, sh-format
 msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:643
+#: git-submodule.sh:667
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr ""
 
-#: git-submodule.sh:648
+#: git-submodule.sh:672
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:649
+#: git-submodule.sh:673
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr ""
 
-#: git-submodule.sh:671 git-submodule.sh:995
+#: git-submodule.sh:695 git-submodule.sh:1017
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr ""
 
-#: git-submodule.sh:779
+#: git-submodule.sh:803
 msgid "The --cached option cannot be used with the --files option"
 msgstr ""
 
 #. unexpected type
-#: git-submodule.sh:819
+#: git-submodule.sh:843
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr ""
 
-#: git-submodule.sh:837
+#: git-submodule.sh:861
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr ""
 
-#: git-submodule.sh:840
+#: git-submodule.sh:864
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr ""
 
-#: git-submodule.sh:843
+#: git-submodule.sh:867
 #, sh-format
 msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 msgstr ""
 
-#: git-submodule.sh:868
+#: git-submodule.sh:892
 msgid "blob"
 msgstr ""
 
-#: git-submodule.sh:906
+#: git-submodule.sh:930
 msgid "# Submodules changed but not updated:"
 msgstr ""
 
-#: git-submodule.sh:908
+#: git-submodule.sh:932
 msgid "# Submodule changes to be committed:"
 msgstr ""
 
-#: git-submodule.sh:1054
+#: git-submodule.sh:1080
 #, sh-format
-msgid "Synchronizing submodule url for '$name'"
+msgid "Synchronizing submodule url for '$prefix$sm_path'"
 msgstr ""
index 9b3aa74..ee6b0fc 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 1.7.12\n"
+"Project-Id-Version: git 1.8.1\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-10-16 08:38+0800\n"
-"PO-Revision-Date: 2012-10-16 08:36+0100\n"
+"POT-Creation-Date: 2012-11-30 12:40+0800\n"
+"PO-Revision-Date: 2012-11-30 10:49+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -65,7 +65,7 @@ msgstr "fmt"
 msgid "archive format"
 msgstr "arkivformat"
 
-#: archive.c:323 builtin/log.c:1079
+#: archive.c:323 builtin/log.c:1084
 msgid "prefix"
 msgstr "prefix"
 
@@ -73,9 +73,9 @@ msgstr "prefix"
 msgid "prepend prefix to each pathname in the archive"
 msgstr "lägg till prefix till varje sökväg i arkivet"
 
-#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2389
-#: builtin/blame.c:2390 builtin/config.c:56 builtin/fast-export.c:642
-#: builtin/fast-export.c:644 builtin/grep.c:801 builtin/hash-object.c:77
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390
+#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77
 #: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540
 #: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149
 msgid "file"
@@ -125,6 +125,14 @@ msgstr "kommando"
 msgid "path to the remote git-upload-archive command"
 msgstr "sökväg till kommandot git-upload-archive på fjärren"
 
+#: attr.c:259
+msgid ""
+"Negative patterns are forbidden in git attributes\n"
+"Use '\\!' for literal leading exclamation."
+msgstr ""
+"Negativa mönster är förbjudna i git-attribut\n"
+"Använd '\\!' för att inleda med ett utropstecken."
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
@@ -135,7 +143,7 @@ msgstr "'%s' ser inte ut som en v2-bundle-fil"
 msgid "unrecognized header: %s%s (%d)"
 msgstr "okänt huvud: %s%s (%d)"
 
-#: bundle.c:89 builtin/commit.c:672
+#: bundle.c:89 builtin/commit.c:674
 #, c-format
 msgid "could not open '%s'"
 msgstr "kunde inte öppna \"%s\""
@@ -145,7 +153,7 @@ msgid "Repository lacks these prerequisite commits:"
 msgstr "Arkivet saknar dessa nödvändiga incheckningar:"
 
 #: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290
-#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
+#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
 msgstr "misslyckades skapa revisionstraversering"
@@ -172,7 +180,7 @@ msgstr[1] "Paketet (bundlen) kräver dessa %d referenser"
 msgid "rev-list died"
 msgstr "rev-list dog"
 
-#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "okänt argument: %s"
@@ -298,17 +306,22 @@ msgid_plural "%lu years ago"
 msgstr[0] "%lu år sedan"
 msgstr[1] "%lu år sedan"
 
-#: diff.c:105
+#: diff.c:111
+#, c-format
+msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
+msgstr "  Misslyckades tolka dirstat-avskärningsprocentandel \"%s\"\n"
+
+#: diff.c:116
 #, c-format
-msgid "  Failed to parse dirstat cut-off percentage '%.*s'\n"
-msgstr "  Misslyckades tolka dirstat-avskärningsprocentandel \"%.*s\"\n"
+msgid "  Unknown dirstat parameter '%s'\n"
+msgstr "  Okänd dirstat-parameter \"%s\"\n"
 
-#: diff.c:110
+#: diff.c:194
 #, c-format
-msgid "  Unknown dirstat parameter '%.*s'\n"
-msgstr "  Okänd dirstat-parameter \"%.*s\"\n"
+msgid "Unknown value for 'diff.submodule' config variable: '%s'"
+msgstr "Okänt värde för konfigurationsvariabeln \"diff.submodule\": \"%s\""
 
-#: diff.c:210
+#: diff.c:237
 #, c-format
 msgid ""
 "Found errors in 'diff.dirstat' config variable:\n"
@@ -317,7 +330,7 @@ msgstr ""
 "Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n"
 "%s"
 
-#: diff.c:3458
+#: diff.c:3494
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -326,6 +339,11 @@ msgstr ""
 "Misslyckades tolka argument till flaggan --dirstat/-X;\n"
 "%s"
 
+#: diff.c:3508
+#, c-format
+msgid "Failed to parse --submodule option parameter: '%s'"
+msgstr "Misslyckades tolka argument till flaggan --submodule: \"%s\""
+
 #: gpg-interface.c:59
 msgid "could not run gpg."
 msgstr "kunde inte köra gpg."
@@ -338,17 +356,17 @@ msgstr "gpg godtog inte data"
 msgid "gpg failed to sign the data"
 msgstr "gpg misslyckades signera data"
 
-#: grep.c:1441
+#: grep.c:1622
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "\"%s\" kunde inte läsa %s"
 
-#: grep.c:1458
+#: grep.c:1639
 #, c-format
 msgid "'%s': %s"
 msgstr "\"%s\": %s"
 
-#: grep.c:1469
+#: grep.c:1650
 #, c-format
 msgid "'%s': short read %s"
 msgstr "\"%s\": kort läsning %s"
@@ -408,6 +426,15 @@ msgstr[1] ""
 "\n"
 "Menade du ett av dessa?"
 
+#: merge.c:56
+msgid "failed to read the cache"
+msgstr "misslyckads läsa cachen"
+
+#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
+#: builtin/clone.c:586
+msgid "unable to write new index file"
+msgstr "kunde inte skriva ny indexfil"
+
 #: merge-recursive.c:190
 #, c-format
 msgid "(bad commit)\n"
@@ -587,7 +614,7 @@ msgstr "Hoppade över %s (sammanslagen samma som befintlig)"
 msgid "Auto-merging %s"
 msgstr "Slår ihop %s automatiskt"
 
-#: merge-recursive.c:1633 git-submodule.sh:869
+#: merge-recursive.c:1633 git-submodule.sh:893
 msgid "submodule"
 msgstr "undermodul"
 
@@ -658,7 +685,7 @@ msgstr "sammanslagningen returnerade ingen incheckning"
 msgid "Could not parse object '%s'"
 msgstr "Kunde inte tolka objektet \"%s\""
 
-#: merge-recursive.c:2009 builtin/merge.c:696
+#: merge-recursive.c:2009 builtin/merge.c:643
 msgid "Unable to write index."
 msgstr "Kunde inte skriva indexet."
 
@@ -690,7 +717,11 @@ msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
 msgstr[0] "Din gren ligger före \"%s\" med %d incheckning.\n"
 msgstr[1] "Din gren ligger före \"%s\" med %d incheckningar.\n"
 
-#: remote.c:1638
+#: remote.c:1637
+msgid "  (use \"git push\" to publish your local commits)\n"
+msgstr "  (använd \"git push\" för att publicera dina lokala incheckningar)\n"
+
+#: remote.c:1640
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
@@ -700,7 +731,11 @@ msgstr[0] ""
 msgstr[1] ""
 "Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n"
 
-#: remote.c:1646
+#: remote.c:1647
+msgid "  (use \"git pull\" to update your local branch)\n"
+msgstr "  (använd \"git pull\" för att uppdatera din lokala gren)\n"
+
+#: remote.c:1650
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -715,14 +750,18 @@ msgstr[1] ""
 "Din gren och \"%s\" har divergerat,\n"
 "och har %d respektive %d olika incheckningar.\n"
 
-#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
-#: builtin/merge.c:1087 builtin/merge.c:1097
+#: remote.c:1659
+msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
+msgstr "  (använd \"git pull\" för att slå ihop fjärrgrenen med din egen)\n"
+
+#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
+#: builtin/merge.c:994
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "Kunde inte öppna \"%s\" för skrivning"
 
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
-#: builtin/merge.c:1089 builtin/merge.c:1102
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
+#: builtin/merge.c:999
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "Kunde inte skriva till \"%s\""
@@ -1348,7 +1387,7 @@ msgstr "git add [flaggor] [--] <filmönster>..."
 msgid "unexpected diff status %c"
 msgstr "diff-status %c förväntades inte"
 
-#: builtin/add.c:67 builtin/commit.c:230
+#: builtin/add.c:67 builtin/commit.c:231
 msgid "updating files failed"
 msgstr "misslyckades uppdatera filer"
 
@@ -1366,7 +1405,7 @@ msgstr "Sökvägen \"%s\" är i undermodulen \"%.*s\""
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Ospårade ändringar efter att ha uppdaterat indexet:"
 
-#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer"
@@ -1409,12 +1448,12 @@ msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\n"
 
 #: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
 #: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
-#: builtin/rm.c:133
+#: builtin/rm.c:206
 msgid "dry run"
 msgstr "testkörning"
 
-#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1154
-#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483
 #: builtin/mv.c:62 builtin/read-tree.c:112
 msgid "be verbose"
 msgstr "var pratsam"
@@ -1423,7 +1462,7 @@ msgstr "var pratsam"
 msgid "interactive picking"
 msgstr "plocka interaktivt"
 
-#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248
 msgid "select hunks interactively"
 msgstr "välj stycken interaktivt"
 
@@ -1490,12 +1529,12 @@ msgstr "Inget angivet, inget tillagt.\n"
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "Kanske menade du att skriva \"git add .\"?\n"
 
-#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
-#: builtin/rm.c:162
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82
+#: builtin/rm.c:235
 msgid "index file corrupt"
 msgstr "indexfilen trasig"
 
-#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370
 msgid "Unable to write new index file"
 msgstr "Kunde inte skriva ny indexfil"
 
@@ -2031,95 +2070,95 @@ msgstr "git blame [flaggor] [rev-flaggor] [rev] [--] fil"
 msgid "[rev-opts] are documented in git-rev-list(1)"
 msgstr "[rev-flaggor] dokumenteras i git-rev-list(1)"
 
-#: builtin/blame.c:2373
+#: builtin/blame.c:2374
 msgid "Show blame entries as we find them, incrementally"
 msgstr "Visa klandringsposter när vi hittar dem, interaktivt"
 
-#: builtin/blame.c:2374
+#: builtin/blame.c:2375
 msgid "Show blank SHA-1 for boundary commits (Default: off)"
 msgstr "Visa blank SHA-1 för gränsincheckningar (Standard: av)"
 
-#: builtin/blame.c:2375
+#: builtin/blame.c:2376
 msgid "Do not treat root commits as boundaries (Default: off)"
 msgstr "Behandla inte rotincheckningar som gränser (Standard: av)"
 
-#: builtin/blame.c:2376
+#: builtin/blame.c:2377
 msgid "Show work cost statistics"
 msgstr "Visa statistik över arbetskostnad"
 
-#: builtin/blame.c:2377
+#: builtin/blame.c:2378
 msgid "Show output score for blame entries"
 msgstr "Visa utdatapoäng för klandringsposter"
 
-#: builtin/blame.c:2378
+#: builtin/blame.c:2379
 msgid "Show original filename (Default: auto)"
 msgstr "Visa originalfilnamn (Standard: auto)"
 
-#: builtin/blame.c:2379
+#: builtin/blame.c:2380
 msgid "Show original linenumber (Default: off)"
 msgstr "Visa ursprungligt radnummer (Standard: av)"
 
-#: builtin/blame.c:2380
+#: builtin/blame.c:2381
 msgid "Show in a format designed for machine consumption"
 msgstr "Visa i ett format avsett för maskinkonsumtion"
 
-#: builtin/blame.c:2381
+#: builtin/blame.c:2382
 msgid "Show porcelain format with per-line commit information"
 msgstr "Visa porslinsformat med per-rad-incheckningsinformation"
 
-#: builtin/blame.c:2382
+#: builtin/blame.c:2383
 msgid "Use the same output mode as git-annotate (Default: off)"
 msgstr "Använd samma utdataläge som git-annotate (Standard: av)"
 
-#: builtin/blame.c:2383
+#: builtin/blame.c:2384
 msgid "Show raw timestamp (Default: off)"
 msgstr "Visa rå tidsstämpel (Standard: av)"
 
-#: builtin/blame.c:2384
+#: builtin/blame.c:2385
 msgid "Show long commit SHA1 (Default: off)"
 msgstr "Visa lång inchecknings-SHA1 (Standard: av)"
 
-#: builtin/blame.c:2385
+#: builtin/blame.c:2386
 msgid "Suppress author name and timestamp (Default: off)"
 msgstr "Undertryck författarnamn och tidsstämpel (Standard: av)"
 
-#: builtin/blame.c:2386
+#: builtin/blame.c:2387
 msgid "Show author email instead of name (Default: off)"
 msgstr "Visa författarens e-post istället för namn (Standard: av)"
 
-#: builtin/blame.c:2387
+#: builtin/blame.c:2388
 msgid "Ignore whitespace differences"
 msgstr "Ignorera ändringar i blanksteg"
 
-#: builtin/blame.c:2388
+#: builtin/blame.c:2389
 msgid "Spend extra cycles to find better match"
 msgstr "Slösa extra cykler med att hitta bättre träff"
 
-#: builtin/blame.c:2389
+#: builtin/blame.c:2390
 msgid "Use revisions from <file> instead of calling git-rev-list"
 msgstr "Använd revisioner från <fil> istället för att anropa git-rev-list"
 
-#: builtin/blame.c:2390
+#: builtin/blame.c:2391
 msgid "Use <file>'s contents as the final image"
 msgstr "Använd <fil>s innehåll som slutgiltig bild"
 
-#: builtin/blame.c:2391 builtin/blame.c:2392
+#: builtin/blame.c:2392 builtin/blame.c:2393
 msgid "score"
 msgstr "poäng"
 
-#: builtin/blame.c:2391
+#: builtin/blame.c:2392
 msgid "Find line copies within and across files"
 msgstr "Hitta kopierade rader inuti och mellan filer"
 
-#: builtin/blame.c:2392
+#: builtin/blame.c:2393
 msgid "Find line movements within and across files"
 msgstr "Hitta flyttade rader inuti och mellan filer"
 
-#: builtin/blame.c:2393
+#: builtin/blame.c:2394
 msgid "n,m"
 msgstr "n,m"
 
-#: builtin/blame.c:2393
+#: builtin/blame.c:2394
 msgid "Process only line range n,m, counting from 1"
 msgstr "Behandla endast radintervallet n,m, med början på 1"
 
@@ -2157,267 +2196,267 @@ msgstr ""
 "tar inte bort grenen \"%s\" som inte har slagits ihop med\n"
 "         \"%s\", trots att den har slagits ihop med HEAD."
 
-#: builtin/branch.c:181
+#: builtin/branch.c:163
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\""
+
+#: builtin/branch.c:167
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+"Grenen \"%s\" har inte slagits samman i sin helhet.\n"
+"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"."
+
+#: builtin/branch.c:180
+msgid "Update of config-file failed"
+msgstr "Misslyckades uppdatera konfigurationsfil"
+
+#: builtin/branch.c:208
 msgid "cannot use -a with -d"
 msgstr "kan inte ange -a med -d"
 
-#: builtin/branch.c:187
+#: builtin/branch.c:214
 msgid "Couldn't look up commit object for HEAD"
 msgstr "Kunde inte slå upp incheckningsobjekt för HEAD"
 
-#: builtin/branch.c:192
+#: builtin/branch.c:222
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
 msgstr "Kan inte ta bort grenen \"%s\" som du befinner dig på för närvarande."
 
-#: builtin/branch.c:203
+#: builtin/branch.c:235
 #, c-format
 msgid "remote branch '%s' not found."
 msgstr "fjärrgrenen \"%s\" hittades inte."
 
-#: builtin/branch.c:204
+#: builtin/branch.c:236
 #, c-format
 msgid "branch '%s' not found."
 msgstr "grenen \"%s\" hittades inte."
 
-#: builtin/branch.c:211
-#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\""
-
-#: builtin/branch.c:217
-#, c-format
-msgid ""
-"The branch '%s' is not fully merged.\n"
-"If you are sure you want to delete it, run 'git branch -D %s'."
-msgstr ""
-"Grenen \"%s\" har inte slagits samman i sin helhet.\n"
-"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"."
-
-#: builtin/branch.c:226
+#: builtin/branch.c:250
 #, c-format
 msgid "Error deleting remote branch '%s'"
 msgstr "Fel vid borttagning av fjärrgrenen \"%s\""
 
-#: builtin/branch.c:227
+#: builtin/branch.c:251
 #, c-format
 msgid "Error deleting branch '%s'"
 msgstr "Fel vid borttagning av grenen \"%s\""
 
-#: builtin/branch.c:234
+#: builtin/branch.c:258
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr "Tog bort fjärrgrenen %s (var %s).\n"
 
-#: builtin/branch.c:235
+#: builtin/branch.c:259
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
 msgstr "Tog bort grenen %s (var %s).\n"
 
-#: builtin/branch.c:240
-msgid "Update of config-file failed"
-msgstr "Misslyckades uppdatera konfigurationsfil"
-
-#: builtin/branch.c:338
+#: builtin/branch.c:361
 #, c-format
 msgid "branch '%s' does not point at a commit"
 msgstr "grenen \"%s\" pekar inte på en incheckning"
 
-#: builtin/branch.c:410
+#: builtin/branch.c:433
 #, c-format
 msgid "[%s: behind %d]"
 msgstr "[%s: bakom %d] "
 
-#: builtin/branch.c:412
+#: builtin/branch.c:435
 #, c-format
 msgid "[behind %d]"
 msgstr "[bakom %d] "
 
-#: builtin/branch.c:416
+#: builtin/branch.c:439
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr "[%s: före %d] "
 
-#: builtin/branch.c:418
+#: builtin/branch.c:441
 #, c-format
 msgid "[ahead %d]"
 msgstr "[före %d] "
 
-#: builtin/branch.c:421
+#: builtin/branch.c:444
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr "[%s: före %d, bakom %d] "
 
-#: builtin/branch.c:424
+#: builtin/branch.c:447
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr "[före %d, bakom %d] "
 
-#: builtin/branch.c:537
+#: builtin/branch.c:560
 msgid "(no branch)"
 msgstr "(ingen gren)"
 
-#: builtin/branch.c:602
+#: builtin/branch.c:625
 msgid "some refs could not be read"
 msgstr "vissa referenser kunde inte läsas"
 
-#: builtin/branch.c:615
+#: builtin/branch.c:638
 msgid "cannot rename the current branch while not on any."
 msgstr ""
 "kunde inte byta namn på aktuell gren när du inte befinner dig på någon."
 
-#: builtin/branch.c:625
+#: builtin/branch.c:648
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Felaktigt namn på gren: \"%s\""
 
-#: builtin/branch.c:640
+#: builtin/branch.c:663
 msgid "Branch rename failed"
 msgstr "Misslyckades byta namn på gren"
 
-#: builtin/branch.c:644
+#: builtin/branch.c:667
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
 msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\""
 
-#: builtin/branch.c:648
+#: builtin/branch.c:671
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr "Grenen namnbytt till %s, men HEAD har inte uppdaterats!"
 
-#: builtin/branch.c:655
+#: builtin/branch.c:678
 msgid "Branch is renamed, but update of config-file failed"
 msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen"
 
-#: builtin/branch.c:670
+#: builtin/branch.c:693
 #, c-format
 msgid "malformed object name %s"
 msgstr "felformat objektnamn %s"
 
-#: builtin/branch.c:694
+#: builtin/branch.c:717
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr "kunde inte skriva grenbeskrivningsmall: %s"
 
-#: builtin/branch.c:724
+#: builtin/branch.c:747
 msgid "Generic options"
 msgstr "Allmänna flaggor"
 
-#: builtin/branch.c:726
+#: builtin/branch.c:749
 msgid "show hash and subject, give twice for upstream branch"
 msgstr "visa hash och ärenderad, ange två gånger för uppströmsgren"
 
-#: builtin/branch.c:727
+#: builtin/branch.c:750
 msgid "suppress informational messages"
 msgstr "undertryck informationsmeddelanden"
 
-#: builtin/branch.c:728
+#: builtin/branch.c:751
 msgid "set up tracking mode (see git-pull(1))"
 msgstr "ställ in spårningsläge (se git-pull(1))"
 
-#: builtin/branch.c:730
+#: builtin/branch.c:753
 msgid "change upstream info"
 msgstr "ändra uppströmsinformation"
 
-#: builtin/branch.c:734
+#: builtin/branch.c:757
 msgid "use colored output"
 msgstr "använd färgad utdata"
 
-#: builtin/branch.c:735
+#: builtin/branch.c:758
 msgid "act on remote-tracking branches"
 msgstr "arbeta på fjärrspårande grenar"
 
-#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
-#: builtin/branch.c:771 builtin/commit.c:1362 builtin/commit.c:1363
-#: builtin/commit.c:1364 builtin/commit.c:1365 builtin/tag.c:470
+#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
+#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377
+#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470
 msgid "commit"
 msgstr "incheckning"
 
-#: builtin/branch.c:739 builtin/branch.c:745
+#: builtin/branch.c:762 builtin/branch.c:768
 msgid "print only branches that contain the commit"
 msgstr "visa endast grenar som innehåller incheckningen"
 
-#: builtin/branch.c:751
+#: builtin/branch.c:774
 msgid "Specific git-branch actions:"
 msgstr "Specifika git-branch-åtgärder:"
 
-#: builtin/branch.c:752
+#: builtin/branch.c:775
 msgid "list both remote-tracking and local branches"
 msgstr "visa både fjärrspårande och lokala grenar"
 
-#: builtin/branch.c:754
+#: builtin/branch.c:777
 msgid "delete fully merged branch"
 msgstr "ta bort helt sammanslagen gren"
 
-#: builtin/branch.c:755
+#: builtin/branch.c:778
 msgid "delete branch (even if not merged)"
 msgstr "ta bort gren (även om inte helt sammanslagen)"
 
-#: builtin/branch.c:756
+#: builtin/branch.c:779
 msgid "move/rename a branch and its reflog"
 msgstr "flytta/ta bort en gren och dess reflogg"
 
-#: builtin/branch.c:757
+#: builtin/branch.c:780
 msgid "move/rename a branch, even if target exists"
 msgstr "flytta/ta bort en gren, även om målet finns"
 
-#: builtin/branch.c:758
+#: builtin/branch.c:781
 msgid "list branch names"
 msgstr "lista namn på grenar"
 
-#: builtin/branch.c:759
+#: builtin/branch.c:782
 msgid "create the branch's reflog"
 msgstr "skapa grenens reflogg"
 
-#: builtin/branch.c:761
+#: builtin/branch.c:784
 msgid "edit the description for the branch"
 msgstr "redigera beskrivning för grenen"
 
-#: builtin/branch.c:762
+#: builtin/branch.c:785
 msgid "force creation (when already exists)"
 msgstr "tvinga skapande (när den redan finns)"
 
-#: builtin/branch.c:765
+#: builtin/branch.c:788
 msgid "print only not merged branches"
 msgstr "visa endast ej sammanslagna grenar"
 
-#: builtin/branch.c:771
+#: builtin/branch.c:794
 msgid "print only merged branches"
 msgstr "visa endast sammanslagna grenar"
 
-#: builtin/branch.c:775
+#: builtin/branch.c:798
 msgid "list branches in columns"
 msgstr "visa grenar i spalter"
 
-#: builtin/branch.c:788
+#: builtin/branch.c:811
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "Misslyckades slå upp HEAD som giltig referens"
 
-#: builtin/branch.c:793 builtin/clone.c:561
+#: builtin/branch.c:816 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr "HEAD hittades inte under refs/heads!"
 
-#: builtin/branch.c:813
+#: builtin/branch.c:836
 msgid "--column and --verbose are incompatible"
 msgstr "--column och --verbose är inkompatibla"
 
-#: builtin/branch.c:864
+#: builtin/branch.c:887
 #, c-format
 msgid "branch '%s' does not exist"
 msgstr "grenen \"%s\" finns inte"
 
-#: builtin/branch.c:876
+#: builtin/branch.c:899
 #, c-format
 msgid "Branch '%s' has no upstream information"
 msgstr "Grenen \"%s\" har ingen uppströmsinformation"
 
-#: builtin/branch.c:891
+#: builtin/branch.c:914
 msgid "-a and -r options to 'git branch' do not make sense with a branch name"
 msgstr ""
 "flaggorna -a och -r på \"git branch\" kan inte anges tillsammans med ett "
 "grennamn"
 
-#: builtin/branch.c:894
+#: builtin/branch.c:917
 #, c-format
 msgid ""
 "The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -2426,7 +2465,7 @@ msgstr ""
 "Flaggan --set-upstream rekommenderas ej och kommer tas bort. Använd --track "
 "eller --set-upstream-to\n"
 
-#: builtin/branch.c:911
+#: builtin/branch.c:934
 #, c-format
 msgid ""
 "\n"
@@ -2437,12 +2476,12 @@ msgstr ""
 "Om du vill göra så att \"%s\" spårar \"%s\" gör du så här:\n"
 "\n"
 
-#: builtin/branch.c:912
+#: builtin/branch.c:935
 #, c-format
 msgid "    git branch -d %s\n"
 msgstr "    git branch -d %s\n"
 
-#: builtin/branch.c:913
+#: builtin/branch.c:936
 #, c-format
 msgid "    git branch --set-upstream-to %s\n"
 msgstr "    git branch --set-upstream-to %s\n"
@@ -2631,11 +2670,6 @@ msgstr "indexfilen är trasig"
 msgid "path '%s' is unmerged"
 msgstr "sökvägen \"%s\" har inte slagits ihop"
 
-#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586
-#: builtin/merge.c:811
-msgid "unable to write new index file"
-msgstr "kunde inte skriva ny indexfil"
-
 #: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
 msgstr "du måste lösa ditt befintliga index först"
@@ -2664,7 +2698,7 @@ msgstr "Redan på \"%s\"\n"
 msgid "Switched to and reset branch '%s'\n"
 msgstr "Växlade till och nollställde grenen \"%s\"\n"
 
-#: builtin/checkout.c:618
+#: builtin/checkout.c:618 builtin/checkout.c:955
 #, c-format
 msgid "Switched to a new branch '%s'\n"
 msgstr "Växlade till en ny gren \"%s\"\n"
@@ -2742,112 +2776,112 @@ msgstr "felaktig referens: %s"
 msgid "reference is not a tree: %s"
 msgstr "referensen är inte ett träd: %s"
 
-#: builtin/checkout.c:961
+#: builtin/checkout.c:964
 msgid "paths cannot be used with switching branches"
 msgstr "sökvägar kan inte användas vid byte av gren"
 
-#: builtin/checkout.c:964 builtin/checkout.c:968
+#: builtin/checkout.c:967 builtin/checkout.c:971
 #, c-format
 msgid "'%s' cannot be used with switching branches"
 msgstr "\"%s\" kan inte användas vid byte av gren"
 
-#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
-#: builtin/checkout.c:983
+#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
+#: builtin/checkout.c:986
 #, c-format
 msgid "'%s' cannot be used with '%s'"
 msgstr "\"%s\" kan inte användas med \"%s\""
 
-#: builtin/checkout.c:988
+#: builtin/checkout.c:991
 #, c-format
 msgid "Cannot switch branch to a non-commit '%s'"
 msgstr "Kan inte växla gren till icke-incheckningen \"%s\""
 
-#: builtin/checkout.c:1009 builtin/gc.c:177
+#: builtin/checkout.c:1012 builtin/gc.c:177
 msgid "suppress progress reporting"
 msgstr "undertryck förloppsrapportering"
 
-#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
 #: builtin/remote.c:169 builtin/remote.c:171
 msgid "branch"
 msgstr "gren"
 
-#: builtin/checkout.c:1011
+#: builtin/checkout.c:1014
 msgid "create and checkout a new branch"
 msgstr "skapa och checka ut en ny gren"
 
-#: builtin/checkout.c:1013
+#: builtin/checkout.c:1016
 msgid "create/reset and checkout a branch"
 msgstr "skapa/nollställ och checka ut en gren"
 
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1017
 msgid "create reflog for new branch"
 msgstr "skapa reflogg för ny gren"
 
-#: builtin/checkout.c:1015
+#: builtin/checkout.c:1018
 msgid "detach the HEAD at named commit"
 msgstr "koppla från HEAD vid namngiven incheckning"
 
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1019
 msgid "set upstream info for new branch"
 msgstr "sätt uppströmsinformation för ny gren"
 
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1021
 msgid "new branch"
 msgstr "ny gren"
 
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1021
 msgid "new unparented branch"
 msgstr "ny gren utan förälder"
 
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1022
 msgid "checkout our version for unmerged files"
 msgstr "checka ut vår version för ej sammanslagna filer"
 
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1024
 msgid "checkout their version for unmerged files"
 msgstr "checka ut deras version för ej sammanslagna filer"
 
-#: builtin/checkout.c:1023
+#: builtin/checkout.c:1026
 msgid "force checkout (throw away local modifications)"
 msgstr "tvinga utcheckning (kasta bort lokala ändringar)"
 
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1027
 msgid "perform a 3-way merge with the new branch"
 msgstr "utför en 3-vägssammanslagning för den nya grenen"
 
-#: builtin/checkout.c:1025 builtin/merge.c:215
+#: builtin/checkout.c:1028 builtin/merge.c:215
 msgid "update ignored files (default)"
 msgstr "uppdatera ignorerade filer (standard)"
 
-#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241
 msgid "style"
 msgstr "stil"
 
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1030
 msgid "conflict style (merge or diff3)"
 msgstr "konfliktstil (merge eller diff3)"
 
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1033
 msgid "second guess 'git checkout no-such-branch'"
 msgstr "förutspå \"git checkout gren-saknas\""
 
-#: builtin/checkout.c:1054
+#: builtin/checkout.c:1057
 msgid "-b, -B and --orphan are mutually exclusive"
 msgstr "-b, -B och --orphan är ömsesidigt uteslutande"
 
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1074
 msgid "--track needs a branch name"
 msgstr "--track behöver ett namn på en gren"
 
-#: builtin/checkout.c:1078
+#: builtin/checkout.c:1081
 msgid "Missing branch name; try -b"
 msgstr "Grennamn saknas; försök med -b"
 
-#: builtin/checkout.c:1113
+#: builtin/checkout.c:1116
 msgid "invalid path specification"
 msgstr "felaktig sökvägsangivelse"
 
-#: builtin/checkout.c:1120
+#: builtin/checkout.c:1123
 #, c-format
 msgid ""
 "Cannot update paths and switch to branch '%s' at the same time.\n"
@@ -2856,12 +2890,12 @@ msgstr ""
 "Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt.\n"
 "Ville du checka ut \"%s\" som inte kan lösas som en utcheckning?"
 
-#: builtin/checkout.c:1125
+#: builtin/checkout.c:1128
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr "git checkout: --detach tar inte en sökväg som argument \"%s\""
 
-#: builtin/checkout.c:1129
+#: builtin/checkout.c:1132
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
@@ -2886,8 +2920,8 @@ msgstr "tvinga"
 msgid "remove whole directories"
 msgstr "ta bort hela kataloger"
 
-#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:803
-#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182
 msgid "pattern"
 msgstr "mönster"
 
@@ -3012,7 +3046,7 @@ msgstr "checka ut <gren> istället för fjärrens HEAD"
 msgid "path to git-upload-pack on the remote"
 msgstr "sökväg till git-upload-pack på fjärren"
 
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:748
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
 msgid "depth"
 msgstr "djup"
 
@@ -3247,93 +3281,93 @@ msgstr ""
 "\n"
 "Annars använder du \"git reset\"\n"
 
-#: builtin/commit.c:257
+#: builtin/commit.c:258
 msgid "failed to unpack HEAD tree object"
 msgstr "misslyckades packa upp HEAD:s trädobjekt"
 
-#: builtin/commit.c:299
+#: builtin/commit.c:300
 msgid "unable to create temporary index"
 msgstr "kunde inte skapa temporär indexfil"
 
-#: builtin/commit.c:305
+#: builtin/commit.c:306
 msgid "interactive add failed"
 msgstr "interaktiv tilläggning misslyckades"
 
-#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
+#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
 msgid "unable to write new_index file"
 msgstr "kunde inte skriva filen new_index"
 
-#: builtin/commit.c:390
+#: builtin/commit.c:391
 msgid "cannot do a partial commit during a merge."
 msgstr "kan inte utföra en delvis incheckning under en sammanslagning."
 
-#: builtin/commit.c:392
+#: builtin/commit.c:393
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr "kan inte utföra en delvis incheckning under en cherry-pick."
 
-#: builtin/commit.c:402
+#: builtin/commit.c:403
 msgid "cannot read the index"
 msgstr "kan inte läsa indexet"
 
-#: builtin/commit.c:422
+#: builtin/commit.c:423
 msgid "unable to write temporary index file"
 msgstr "kunde inte skriva temporär indexfil"
 
-#: builtin/commit.c:509 builtin/commit.c:515
+#: builtin/commit.c:511 builtin/commit.c:517
 #, c-format
 msgid "invalid commit: %s"
 msgstr "felaktig incheckning: %s"
 
-#: builtin/commit.c:538
+#: builtin/commit.c:540
 msgid "malformed --author parameter"
 msgstr "felformad \"--author\"-flagga"
 
-#: builtin/commit.c:558
+#: builtin/commit.c:560
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "Felaktig indragningssträng: \"%s\""
 
-#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
+#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "kunde inte slå upp incheckningen %s"
 
-#: builtin/commit.c:608 builtin/shortlog.c:296
+#: builtin/commit.c:610 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(läser loggmeddelande från standard in)\n"
 
-#: builtin/commit.c:610
+#: builtin/commit.c:612
 msgid "could not read log from standard input"
 msgstr "kunde inte läsa logg från standard in"
 
-#: builtin/commit.c:614
+#: builtin/commit.c:616
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "kunde inte läsa loggfilen \"%s\""
 
-#: builtin/commit.c:620
+#: builtin/commit.c:622
 msgid "commit has empty message"
 msgstr "incheckningen har ett tomt meddelande"
 
-#: builtin/commit.c:636
+#: builtin/commit.c:638
 msgid "could not read MERGE_MSG"
 msgstr "kunde inte läsa MERGE_MSG"
 
-#: builtin/commit.c:640
+#: builtin/commit.c:642
 msgid "could not read SQUASH_MSG"
 msgstr "kunde inte läsa SQUASH_MSG"
 
-#: builtin/commit.c:644
+#: builtin/commit.c:646
 #, c-format
 msgid "could not read '%s'"
 msgstr "kunde inte läsa \"%s\""
 
-#: builtin/commit.c:705
+#: builtin/commit.c:707
 msgid "could not write commit template"
 msgstr "kunde inte skriva incheckningsmall"
 
-#: builtin/commit.c:716
+#: builtin/commit.c:718
 #, c-format
 msgid ""
 "\n"
@@ -3348,7 +3382,7 @@ msgstr ""
 "\t%s\n"
 "och försöker igen.\n"
 
-#: builtin/commit.c:721
+#: builtin/commit.c:723
 #, c-format
 msgid ""
 "\n"
@@ -3363,7 +3397,7 @@ msgstr ""
 "\t%s\n"
 "och försöker igen.\n"
 
-#: builtin/commit.c:733
+#: builtin/commit.c:735
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -3371,7 +3405,7 @@ msgstr ""
 "Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
 "med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n"
 
-#: builtin/commit.c:738
+#: builtin/commit.c:740
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -3381,131 +3415,139 @@ msgstr ""
 "med \"#\" kommer behållas; du kan själv ta bort dem om du vill.\n"
 "Ett tomt meddelande avbryter incheckningen.\n"
 
-#: builtin/commit.c:751
+#: builtin/commit.c:753
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sFörfattare: %s"
 
-#: builtin/commit.c:758
+#: builtin/commit.c:760
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sIncheckare: %s"
 
-#: builtin/commit.c:778
+#: builtin/commit.c:780
 msgid "Cannot read index"
 msgstr "Kan inte läsa indexet"
 
-#: builtin/commit.c:815
+#: builtin/commit.c:817
 msgid "Error building trees"
 msgstr "Fel vid byggande av träd"
 
-#: builtin/commit.c:830 builtin/tag.c:361
+#: builtin/commit.c:832 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "Ange meddelandet en av flaggorna -m eller -F.\n"
 
-#: builtin/commit.c:927
+#: builtin/commit.c:929
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "Hittade ingen befintlig författare med \"%s\""
 
-#: builtin/commit.c:942 builtin/commit.c:1142
+#: builtin/commit.c:944 builtin/commit.c:1148
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Ogiltigt läge för ospårade filer: \"%s\""
 
-#: builtin/commit.c:982
+#: builtin/commit.c:984
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "Kan inte använda både --reset-author och --author"
 
-#: builtin/commit.c:993
+#: builtin/commit.c:995
 msgid "You have nothing to amend."
 msgstr "Du har inget att utöka."
 
-#: builtin/commit.c:996
+#: builtin/commit.c:998
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr "Du är i mitten av en sammanslagning -- kan inte utöka."
 
-#: builtin/commit.c:998
+#: builtin/commit.c:1000
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr "Du är i mitten av en cherry-pick -- kan inte utöka."
 
-#: builtin/commit.c:1001
+#: builtin/commit.c:1003
 msgid "Options --squash and --fixup cannot be used together"
 msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt"
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:1013
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "Endast en av -c/-C/-F/--fixup kan användas."
 
-#: builtin/commit.c:1013
+#: builtin/commit.c:1015
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr "Flaggan -m kan inte kombineras med -c/-C/-F/--fixup."
 
-#: builtin/commit.c:1021
+#: builtin/commit.c:1023
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr "--reset-author kan endast användas med -C, -c eller --amend."
 
-#: builtin/commit.c:1038
+#: builtin/commit.c:1040
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 "Endast en av --include/--only/--all/--interactive/--patch kan användas."
 
-#: builtin/commit.c:1040
+#: builtin/commit.c:1042
 msgid "No paths with --include/--only does not make sense."
 msgstr "Du måste ange sökvägar tillsammans med --include/--only."
 
-#: builtin/commit.c:1042
+#: builtin/commit.c:1044
 msgid "Clever... amending the last one with dirty index."
 msgstr "Smart... utöka den senaste med smutsigt index."
 
-#: builtin/commit.c:1044
+#: builtin/commit.c:1046
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr "Explicita sökvägar angavs utan -i eller -o; antar --only sökvägar..."
 
-#: builtin/commit.c:1054 builtin/tag.c:577
+#: builtin/commit.c:1056 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Felaktigt städningsläge %s"
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1061
 msgid "Paths with -a does not make sense."
 msgstr "Kan inte ange sökvägar med -a."
 
-#: builtin/commit.c:1156 builtin/commit.c:1384
+#: builtin/commit.c:1067 builtin/commit.c:1202
+msgid "--long and -z are incompatible"
+msgstr "--long och -z är inkompatibla"
+
+#: builtin/commit.c:1162 builtin/commit.c:1398
 msgid "show status concisely"
 msgstr "vis koncis status"
 
-#: builtin/commit.c:1158 builtin/commit.c:1386
+#: builtin/commit.c:1164 builtin/commit.c:1400
 msgid "show branch information"
 msgstr "visa information om gren"
 
-#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
+#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389
 msgid "machine-readable output"
 msgstr "maskinläsbar utdata"
 
-#: builtin/commit.c:1163 builtin/commit.c:1390
+#: builtin/commit.c:1169 builtin/commit.c:1404
+msgid "show status in long format (default)"
+msgstr "visa status i långt format (standard)"
+
+#: builtin/commit.c:1172 builtin/commit.c:1407
 msgid "terminate entries with NUL"
 msgstr "terminera poster med NUL"
 
-#: builtin/commit.c:1165 builtin/commit.c:1393 builtin/fast-export.c:636
+#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636
 #: builtin/fast-export.c:639 builtin/tag.c:461
 msgid "mode"
 msgstr "läge"
 
-#: builtin/commit.c:1166 builtin/commit.c:1393
+#: builtin/commit.c:1175 builtin/commit.c:1410
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr "visa ospårade filer, valfria lägen: alla, normal, no. (Standard: all)"
 
-#: builtin/commit.c:1169
+#: builtin/commit.c:1178
 msgid "show ignored files"
 msgstr "visa ignorerade filer"
 
-#: builtin/commit.c:1170 parse-options.h:151
+#: builtin/commit.c:1179 parse-options.h:151
 msgid "when"
 msgstr "när"
 
-#: builtin/commit.c:1171
+#: builtin/commit.c:1180
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
@@ -3513,217 +3555,217 @@ msgstr ""
 "ignorera ändringar i undermoduler, valfritt när: all, dirty, untracked. "
 "(Default: all)"
 
-#: builtin/commit.c:1173
+#: builtin/commit.c:1182
 msgid "list untracked files in columns"
 msgstr "visa ospårade filer i spalter"
 
-#: builtin/commit.c:1242
+#: builtin/commit.c:1256
 msgid "couldn't look up newly created commit"
 msgstr "kunde inte slå upp en precis skapad incheckning"
 
-#: builtin/commit.c:1244
+#: builtin/commit.c:1258
 msgid "could not parse newly created commit"
 msgstr "kunde inte tolka en precis skapad incheckning"
 
-#: builtin/commit.c:1285
+#: builtin/commit.c:1299
 msgid "detached HEAD"
 msgstr "frånkopplad HEAD"
 
-#: builtin/commit.c:1287
+#: builtin/commit.c:1301
 msgid " (root-commit)"
 msgstr " (rotincheckning)"
 
-#: builtin/commit.c:1354
+#: builtin/commit.c:1368
 msgid "suppress summary after successful commit"
 msgstr "undertryck sammanfattning efter framgångsrik incheckning"
 
-#: builtin/commit.c:1355
+#: builtin/commit.c:1369
 msgid "show diff in commit message template"
 msgstr "visa diff i mallen för incheckningsmeddelandet"
 
-#: builtin/commit.c:1357
+#: builtin/commit.c:1371
 msgid "Commit message options"
 msgstr "Alternativ för incheckningsmeddelande"
 
-#: builtin/commit.c:1358 builtin/tag.c:459
+#: builtin/commit.c:1372 builtin/tag.c:459
 msgid "read message from file"
 msgstr "läs meddelande från fil"
 
-#: builtin/commit.c:1359
+#: builtin/commit.c:1373
 msgid "author"
 msgstr "författare"
 
-#: builtin/commit.c:1359
+#: builtin/commit.c:1373
 msgid "override author for commit"
 msgstr "överstyr författare för incheckningen"
 
-#: builtin/commit.c:1360 builtin/gc.c:178
+#: builtin/commit.c:1374 builtin/gc.c:178
 msgid "date"
 msgstr "datum"
 
-#: builtin/commit.c:1360
+#: builtin/commit.c:1374
 msgid "override date for commit"
 msgstr "överstyr datum för inchecknignen"
 
-#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537
 #: builtin/notes.c:694 builtin/tag.c:457
 msgid "message"
 msgstr "meddelande"
 
-#: builtin/commit.c:1361
+#: builtin/commit.c:1375
 msgid "commit message"
 msgstr "incheckningsmeddelande"
 
-#: builtin/commit.c:1362
+#: builtin/commit.c:1376
 msgid "reuse and edit message from specified commit"
 msgstr "återanvänd och redigera meddelande från angiven incheckning"
 
-#: builtin/commit.c:1363
+#: builtin/commit.c:1377
 msgid "reuse message from specified commit"
 msgstr "återanvänd meddelande från angiven incheckning"
 
-#: builtin/commit.c:1364
+#: builtin/commit.c:1378
 msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
 "använd autosquash-formaterat meddelande för att fixa angiven incheckning"
 
-#: builtin/commit.c:1365
+#: builtin/commit.c:1379
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 "använd autosquash-formaterat meddelande för att slå ihop med angiven "
 "incheckning"
 
-#: builtin/commit.c:1366
+#: builtin/commit.c:1380
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr "jag är nu författare av incheckningen (används med -C/-c/--amend)"
 
-#: builtin/commit.c:1367 builtin/log.c:1068 builtin/revert.c:109
+#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109
 msgid "add Signed-off-by:"
 msgstr "lägg till Signed-off-by:"
 
-#: builtin/commit.c:1368
+#: builtin/commit.c:1382
 msgid "use specified template file"
 msgstr "använd angiven mallfil"
 
-#: builtin/commit.c:1369
+#: builtin/commit.c:1383
 msgid "force edit of commit"
 msgstr "tvinga redigering av incheckning"
 
-#: builtin/commit.c:1370
+#: builtin/commit.c:1384
 msgid "default"
 msgstr "standard"
 
-#: builtin/commit.c:1370 builtin/tag.c:462
+#: builtin/commit.c:1384 builtin/tag.c:462
 msgid "how to strip spaces and #comments from message"
 msgstr "hur blanksteg och #kommentarer skall tas bort från meddelande"
 
-#: builtin/commit.c:1371
+#: builtin/commit.c:1385
 msgid "include status in commit message template"
 msgstr "inkludera status i mallen för incheckningsmeddelandet"
 
-#: builtin/commit.c:1372 builtin/merge.c:213 builtin/tag.c:463
+#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463
 msgid "key id"
 msgstr "nyckel-id"
 
-#: builtin/commit.c:1373 builtin/merge.c:214
+#: builtin/commit.c:1387 builtin/merge.c:214
 msgid "GPG sign commit"
 msgstr "GPG-signera incheckning"
 
 #. end commit message options
-#: builtin/commit.c:1376
+#: builtin/commit.c:1390
 msgid "Commit contents options"
 msgstr "Alternativ för incheckningens innehåll"
 
-#: builtin/commit.c:1377
+#: builtin/commit.c:1391
 msgid "commit all changed files"
 msgstr "checka in alla ändrade filer"
 
-#: builtin/commit.c:1378
+#: builtin/commit.c:1392
 msgid "add specified files to index for commit"
 msgstr "lägg till angivna filer till indexet för incheckning"
 
-#: builtin/commit.c:1379
+#: builtin/commit.c:1393
 msgid "interactively add files"
 msgstr "lägg till filer interaktivt"
 
-#: builtin/commit.c:1380
+#: builtin/commit.c:1394
 msgid "interactively add changes"
 msgstr "lägg till ändringar interaktivt"
 
-#: builtin/commit.c:1381
+#: builtin/commit.c:1395
 msgid "commit only specified files"
 msgstr "checka endast in angivna filer"
 
-#: builtin/commit.c:1382
+#: builtin/commit.c:1396
 msgid "bypass pre-commit hook"
 msgstr "förbigå pre-commit-krok"
 
-#: builtin/commit.c:1383
+#: builtin/commit.c:1397
 msgid "show what would be committed"
 msgstr "visa vad som skulle checkas in"
 
-#: builtin/commit.c:1391
+#: builtin/commit.c:1408
 msgid "amend previous commit"
 msgstr "lägg till föregående incheckning"
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1409
 msgid "bypass post-rewrite hook"
 msgstr "förbigå post-rewrite-krok"
 
-#: builtin/commit.c:1397
+#: builtin/commit.c:1414
 msgid "ok to record an empty change"
 msgstr "ok att registrera en tom ändring"
 
-#: builtin/commit.c:1400
+#: builtin/commit.c:1417
 msgid "ok to record a change with an empty message"
 msgstr "ok att registrera en ändring med tomt meddelande"
 
-#: builtin/commit.c:1432
+#: builtin/commit.c:1449
 msgid "could not parse HEAD commit"
 msgstr "kunde inte tolka HEAD:s incheckning"
 
-#: builtin/commit.c:1470 builtin/merge.c:508
+#: builtin/commit.c:1487 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr "kunde inte öppna \"%s\" för läsning"
 
-#: builtin/commit.c:1477
+#: builtin/commit.c:1494
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Trasig MERGE_HEAD-fil (%s)"
 
-#: builtin/commit.c:1484
+#: builtin/commit.c:1501
 msgid "could not read MERGE_MODE"
 msgstr "kunde inte läsa MERGE_MODE"
 
-#: builtin/commit.c:1503
+#: builtin/commit.c:1520
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "kunde inte läsa incheckningsmeddelande: %s"
 
-#: builtin/commit.c:1517
+#: builtin/commit.c:1534
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
 
-#: builtin/commit.c:1522
+#: builtin/commit.c:1539
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n"
 
-#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
+#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857
 msgid "failed to write commit object"
 msgstr "kunde inte skriva incheckningsobjekt"
 
-#: builtin/commit.c:1558
+#: builtin/commit.c:1575
 msgid "cannot lock HEAD ref"
 msgstr "kunde inte låsa HEAD-referens"
 
-#: builtin/commit.c:1562
+#: builtin/commit.c:1579
 msgid "cannot update HEAD ref"
 msgstr "kunde inte uppdatera HEAD-referens"
 
-#: builtin/commit.c:1573
+#: builtin/commit.c:1590
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -3738,115 +3780,115 @@ msgstr ""
 msgid "git config [options]"
 msgstr "git config [flaggor]"
 
-#: builtin/config.c:52
+#: builtin/config.c:51
 msgid "Config file location"
 msgstr "Konfigurationsfilens plats"
 
-#: builtin/config.c:53
+#: builtin/config.c:52
 msgid "use global config file"
 msgstr "använd global konfigurationsfil"
 
-#: builtin/config.c:54
+#: builtin/config.c:53
 msgid "use system config file"
 msgstr "använd systemets konfigurationsfil"
 
-#: builtin/config.c:55
+#: builtin/config.c:54
 msgid "use repository config file"
 msgstr "använd arkivets konfigurationsfil"
 
-#: builtin/config.c:56
+#: builtin/config.c:55
 msgid "use given config file"
 msgstr "använd angiven konfigurationsil"
 
-#: builtin/config.c:57
+#: builtin/config.c:56
 msgid "Action"
 msgstr "Åtgärd"
 
-#: builtin/config.c:58
+#: builtin/config.c:57
 msgid "get value: name [value-regex]"
 msgstr "hämta värde: namn [värde-reguttr]"
 
-#: builtin/config.c:59
+#: builtin/config.c:58
 msgid "get all values: key [value-regex]"
 msgstr "hämta alla värden: nyckel [värde-reguttr]"
 
-#: builtin/config.c:60
+#: builtin/config.c:59
 msgid "get values for regexp: name-regex [value-regex]"
 msgstr "hämta värden för reguttr: namn-reguttr [värde-reguttr]"
 
-#: builtin/config.c:61
+#: builtin/config.c:60
 msgid "replace all matching variables: name value [value_regex]"
 msgstr "ersätt alla motsvarande variabler: namn värde [värde-reguttr]"
 
-#: builtin/config.c:62
+#: builtin/config.c:61
 msgid "add a new variable: name value"
 msgstr "lägg till en ny variabel: namn värde"
 
-#: builtin/config.c:63
+#: builtin/config.c:62
 msgid "remove a variable: name [value-regex]"
 msgstr "ta bort en variabel: namn [värde-reguttr]"
 
-#: builtin/config.c:64
+#: builtin/config.c:63
 msgid "remove all matches: name [value-regex]"
 msgstr "ta bort alla träffar: namn [värde-reguttr]"
 
-#: builtin/config.c:65
+#: builtin/config.c:64
 msgid "rename section: old-name new-name"
 msgstr "byt namn på sektion: gammalt-namn nytt-namn"
 
-#: builtin/config.c:66
+#: builtin/config.c:65
 msgid "remove a section: name"
 msgstr "ta bort en sektion: namn"
 
-#: builtin/config.c:67
+#: builtin/config.c:66
 msgid "list all"
 msgstr "visa alla"
 
-#: builtin/config.c:68
+#: builtin/config.c:67
 msgid "open an editor"
 msgstr "öppna textredigeringsprogram"
 
-#: builtin/config.c:69 builtin/config.c:70
+#: builtin/config.c:68 builtin/config.c:69
 msgid "slot"
 msgstr "plats"
 
-#: builtin/config.c:69
+#: builtin/config.c:68
 msgid "find the color configured: [default]"
 msgstr "hitta den inställda färgen: [default]"
 
-#: builtin/config.c:70
+#: builtin/config.c:69
 msgid "find the color setting: [stdout-is-tty]"
 msgstr "hitta färginställningen: [stdout-is-tty]"
 
-#: builtin/config.c:71
+#: builtin/config.c:70
 msgid "Type"
 msgstr "Typ"
 
-#: builtin/config.c:72
+#: builtin/config.c:71
 msgid "value is \"true\" or \"false\""
 msgstr "värdet är \"true\" eller \"false\""
 
-#: builtin/config.c:73
+#: builtin/config.c:72
 msgid "value is decimal number"
 msgstr "värdet är ett decimalt tal"
 
-#: builtin/config.c:74
+#: builtin/config.c:73
 msgid "value is --bool or --int"
 msgstr "värdet är --bool eller --int"
 
-#: builtin/config.c:75
+#: builtin/config.c:74
 msgid "value is a path (file or directory name)"
 msgstr "värdet är en sökväg (fil- eller katalognamn)"
 
-#: builtin/config.c:76
+#: builtin/config.c:75
 msgid "Other"
 msgstr "Andra"
 
-#: builtin/config.c:77
+#: builtin/config.c:76
 msgid "terminate values with NUL byte"
 msgstr "terminera värden med NUL-byte"
 
-#: builtin/config.c:78
+#: builtin/config.c:77
 msgid "respect include directives on lookup"
 msgstr "respektera inkluderingsdirektiv vid uppslag"
 
@@ -3995,31 +4037,31 @@ msgstr "--dirty är inkompatibelt med \"committish\"-värden"
 msgid "'%s': not a regular file or symlink"
 msgstr "\"%s\": inte en normal fil eller symbolisk länk"
 
-#: builtin/diff.c:224
+#: builtin/diff.c:228
 #, c-format
 msgid "invalid option: %s"
 msgstr "ogiltig flagga: %s"
 
-#: builtin/diff.c:301
+#: builtin/diff.c:305
 msgid "Not a git repository"
 msgstr "Inte ett git-arkiv"
 
-#: builtin/diff.c:344
+#: builtin/diff.c:348
 #, c-format
 msgid "invalid object '%s' given."
 msgstr "objektet \"%s\" som angavs är felaktigt."
 
-#: builtin/diff.c:349
+#: builtin/diff.c:353
 #, c-format
 msgid "more than %d trees given: '%s'"
 msgstr "mer än %d träd angavs: \"%s\""
 
-#: builtin/diff.c:359
+#: builtin/diff.c:363
 #, c-format
 msgid "more than two blobs given: '%s'"
 msgstr "mer än två blobbar angavs: \"%s\""
 
-#: builtin/diff.c:367
+#: builtin/diff.c:371
 #, c-format
 msgid "unhandled object '%s' given."
 msgstr "ej hanterat objekt \"%s\" angavs."
@@ -4132,7 +4174,7 @@ msgstr "tillåt uppdatering av HEAD-referens"
 msgid "deepen history of shallow clone"
 msgstr "fördjupa historik för grund klon"
 
-#: builtin/fetch.c:85 builtin/log.c:1083
+#: builtin/fetch.c:85 builtin/log.c:1088
 msgid "dir"
 msgstr "kat"
 
@@ -4304,8 +4346,8 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
 msgstr ""
 "git fmt-merge-msg [-m <meddelande>] [--log[=<n>]|--no-log] [--file <fil>]"
 
-#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:787
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
 #: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
 msgid "n"
 msgstr "n"
@@ -4465,225 +4507,225 @@ msgstr "git grep [flaggor] [-e] <mönster> [<rev>...] [[--] <sökväg>...]"
 msgid "grep: failed to create thread: %s"
 msgstr "grep: misslyckades skapa tråd. %s"
 
-#: builtin/grep.c:455
+#: builtin/grep.c:365
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Kunde inte byta katalog (chdir): %s"
 
-#: builtin/grep.c:531 builtin/grep.c:565
+#: builtin/grep.c:443 builtin/grep.c:478
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "kunde inte läsa träd (%s)"
 
-#: builtin/grep.c:579
+#: builtin/grep.c:493
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "Kunde inte \"grep\" från objekt av typen %s"
 
-#: builtin/grep.c:637
+#: builtin/grep.c:551
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "flaggan \"%c\" antar ett numeriskt värde"
 
-#: builtin/grep.c:654
+#: builtin/grep.c:568
 #, c-format
 msgid "cannot open '%s'"
 msgstr "kan inte öppna \"%s\""
 
-#: builtin/grep.c:729
+#: builtin/grep.c:643
 msgid "search in index instead of in the work tree"
 msgstr "sök i indexet istället för i arbetskatalogen"
 
-#: builtin/grep.c:731
+#: builtin/grep.c:645
 msgid "find in contents not managed by git"
 msgstr "sök i innehål som inte hanteras av git"
 
-#: builtin/grep.c:733
+#: builtin/grep.c:647
 msgid "search in both tracked and untracked files"
 msgstr "sök i både spårade och ospårade filer"
 
-#: builtin/grep.c:735
+#: builtin/grep.c:649
 msgid "search also in ignored files"
 msgstr "sök även i ignorerade filer"
 
-#: builtin/grep.c:738
+#: builtin/grep.c:652
 msgid "show non-matching lines"
 msgstr "vis rader som inte träffas"
 
-#: builtin/grep.c:740
+#: builtin/grep.c:654
 msgid "case insensitive matching"
 msgstr "skiftlägesokänslig sökning"
 
-#: builtin/grep.c:742
+#: builtin/grep.c:656
 msgid "match patterns only at word boundaries"
 msgstr "matcha endast mönster vid ordgränser"
 
-#: builtin/grep.c:744
+#: builtin/grep.c:658
 msgid "process binary files as text"
 msgstr "hantera binärfiler som text"
 
-#: builtin/grep.c:746
+#: builtin/grep.c:660
 msgid "don't match patterns in binary files"
 msgstr "träffa inte mönster i binärfiler"
 
-#: builtin/grep.c:749
+#: builtin/grep.c:663
 msgid "descend at most <depth> levels"
 msgstr "gå som mest ned <djup> nivåer"
 
-#: builtin/grep.c:753
+#: builtin/grep.c:667
 msgid "use extended POSIX regular expressions"
 msgstr "använd utökade POSIX-reguljära uttryck"
 
-#: builtin/grep.c:756
+#: builtin/grep.c:670
 msgid "use basic POSIX regular expressions (default)"
 msgstr "använd grundläggande POSIX-reguljära uttryck (standard)"
 
-#: builtin/grep.c:759
+#: builtin/grep.c:673
 msgid "interpret patterns as fixed strings"
 msgstr "tolka mönster som fixerade strängar"
 
-#: builtin/grep.c:762
+#: builtin/grep.c:676
 msgid "use Perl-compatible regular expressions"
 msgstr "använd Perlkompatibla reguljära uttryck"
 
-#: builtin/grep.c:765
+#: builtin/grep.c:679
 msgid "show line numbers"
 msgstr "visa radnummer"
 
-#: builtin/grep.c:766
+#: builtin/grep.c:680
 msgid "don't show filenames"
 msgstr "visa inte filnamn"
 
-#: builtin/grep.c:767
+#: builtin/grep.c:681
 msgid "show filenames"
 msgstr "visa filnamn"
 
-#: builtin/grep.c:769
+#: builtin/grep.c:683
 msgid "show filenames relative to top directory"
 msgstr "visa filnamn relativa till toppkatalogen"
 
-#: builtin/grep.c:771
+#: builtin/grep.c:685
 msgid "show only filenames instead of matching lines"
 msgstr "visa endast filnamn istället för träffade rader"
 
-#: builtin/grep.c:773
+#: builtin/grep.c:687
 msgid "synonym for --files-with-matches"
 msgstr "synonym för --files-with-matches"
 
-#: builtin/grep.c:776
+#: builtin/grep.c:690
 msgid "show only the names of files without match"
 msgstr "visa endast namn på filer utan träffar"
 
-#: builtin/grep.c:778
+#: builtin/grep.c:692
 msgid "print NUL after filenames"
 msgstr "skriv NUL efter filnamn"
 
-#: builtin/grep.c:780
+#: builtin/grep.c:694
 msgid "show the number of matches instead of matching lines"
 msgstr "visa antal träffar istället för träffade rader"
 
-#: builtin/grep.c:781
+#: builtin/grep.c:695
 msgid "highlight matches"
 msgstr "ljusmarkera träffar"
 
-#: builtin/grep.c:783
+#: builtin/grep.c:697
 msgid "print empty line between matches from different files"
 msgstr "skriv tomma rader mellan träffar från olika filer"
 
-#: builtin/grep.c:785
+#: builtin/grep.c:699
 msgid "show filename only once above matches from same file"
 msgstr "visa filnamn endast en gång ovanför träffar från samma fil"
 
-#: builtin/grep.c:788
+#: builtin/grep.c:702
 msgid "show <n> context lines before and after matches"
 msgstr "visa <n> rader sammanhang före och efter träffar"
 
-#: builtin/grep.c:791
+#: builtin/grep.c:705
 msgid "show <n> context lines before matches"
 msgstr "visa <n> rader sammanhang före träffar"
 
-#: builtin/grep.c:793
+#: builtin/grep.c:707
 msgid "show <n> context lines after matches"
 msgstr "visa <n> rader sammanhang efter träffar"
 
-#: builtin/grep.c:794
+#: builtin/grep.c:708
 msgid "shortcut for -C NUM"
 msgstr "genväg för -C NUM"
 
-#: builtin/grep.c:797
+#: builtin/grep.c:711
 msgid "show a line with the function name before matches"
 msgstr "visa en rad med funktionsnamnet före träffen"
 
-#: builtin/grep.c:799
+#: builtin/grep.c:713
 msgid "show the surrounding function"
 msgstr "visa den omkringliggande funktionen"
 
-#: builtin/grep.c:802
+#: builtin/grep.c:716
 msgid "read patterns from file"
 msgstr "läs mönster från fil"
 
-#: builtin/grep.c:804
+#: builtin/grep.c:718
 msgid "match <pattern>"
 msgstr "träffa <mönster>"
 
-#: builtin/grep.c:806
+#: builtin/grep.c:720
 msgid "combine patterns specified with -e"
 msgstr "kombinera mönster som anges med -e"
 
-#: builtin/grep.c:818
+#: builtin/grep.c:732
 msgid "indicate hit with exit status without output"
 msgstr "ange träff med slutstatuskod utan utdata"
 
-#: builtin/grep.c:820
+#: builtin/grep.c:734
 msgid "show only matches from files that match all patterns"
 msgstr "visa endast träffar från filer som träffar alla mönster"
 
-#: builtin/grep.c:822
+#: builtin/grep.c:736
 msgid "show parse tree for grep expression"
 msgstr "visa analysträd för grep-uttryck"
 
-#: builtin/grep.c:826
+#: builtin/grep.c:740
 msgid "pager"
 msgstr "bläddrare"
 
-#: builtin/grep.c:826
+#: builtin/grep.c:740
 msgid "show matching files in the pager"
 msgstr "visa träffade filer i filbläddraren"
 
-#: builtin/grep.c:829
+#: builtin/grep.c:743
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "tillåt anropa grep(1) (ignoreras av detta bygge)"
 
-#: builtin/grep.c:830 builtin/show-ref.c:201
+#: builtin/grep.c:744 builtin/show-ref.c:184
 msgid "show usage"
 msgstr "visa användning"
 
-#: builtin/grep.c:921
+#: builtin/grep.c:811
 msgid "no pattern given."
 msgstr "inget mönster angavs."
 
-#: builtin/grep.c:935
+#: builtin/grep.c:825
 #, c-format
 msgid "bad object %s"
 msgstr "felaktigt objekt %s"
 
-#: builtin/grep.c:976
+#: builtin/grep.c:866
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager fungerar endast i arbetskatalogen"
 
-#: builtin/grep.c:999
+#: builtin/grep.c:889
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached och --untracked kan inte användas med --no-index."
 
-#: builtin/grep.c:1004
+#: builtin/grep.c:894
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr "--no-index och --untracked kan inte användas med revisioner."
 
-#: builtin/grep.c:1007
+#: builtin/grep.c:897
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr "--[no-]exclude-standard kan inte användas för spårat innehåll."
 
-#: builtin/grep.c:1015
+#: builtin/grep.c:905
 msgid "both --cached and trees are given."
 msgstr "både --cached och träd angavs."
 
@@ -5277,219 +5319,219 @@ msgstr "dekoreringsflaggor"
 msgid "Final output: %d %s\n"
 msgstr "Slututdata: %d %s\n"
 
-#: builtin/log.c:403 builtin/log.c:494
+#: builtin/log.c:405 builtin/log.c:497
 #, c-format
 msgid "Could not read object %s"
 msgstr "Kunde inte läsa objektet %s"
 
-#: builtin/log.c:518
+#: builtin/log.c:521
 #, c-format
 msgid "Unknown type: %d"
 msgstr "Okänd typ: %d"
 
-#: builtin/log.c:608
+#: builtin/log.c:613
 msgid "format.headers without value"
 msgstr "format.headers utan värde"
 
-#: builtin/log.c:682
+#: builtin/log.c:687
 msgid "name of output directory is too long"
 msgstr "namnet på utdatakatalogen är för långt"
 
-#: builtin/log.c:693
+#: builtin/log.c:698
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr "Kan inte öppna patchfilen %s"
 
-#: builtin/log.c:707
+#: builtin/log.c:712
 msgid "Need exactly one range."
 msgstr "Behöver precis ett intervall."
 
-#: builtin/log.c:715
+#: builtin/log.c:720
 msgid "Not a range."
 msgstr "Inte ett intervall."
 
-#: builtin/log.c:789
+#: builtin/log.c:794
 msgid "Cover letter needs email format"
 msgstr "Omslagsbrevet behöver e-postformat"
 
-#: builtin/log.c:862
+#: builtin/log.c:867
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "tokigt in-reply-to: %s"
 
-#: builtin/log.c:890
+#: builtin/log.c:895
 msgid "git format-patch [options] [<since> | <revision range>]"
 msgstr "git format-patch [flaggor] [<sedan> | <revisionsintervall>]"
 
-#: builtin/log.c:935
+#: builtin/log.c:940
 msgid "Two output directories?"
 msgstr "Två utdatakataloger?"
 
-#: builtin/log.c:1063
+#: builtin/log.c:1068
 msgid "use [PATCH n/m] even with a single patch"
 msgstr "använd [PATCH n/m] även för en ensam patch"
 
-#: builtin/log.c:1066
+#: builtin/log.c:1071
 msgid "use [PATCH] even with multiple patches"
 msgstr "använd [PATCH] även för flera patchar"
 
-#: builtin/log.c:1070
+#: builtin/log.c:1075
 msgid "print patches to standard out"
 msgstr "skriv patcharna på stnadard ut"
 
-#: builtin/log.c:1072
+#: builtin/log.c:1077
 msgid "generate a cover letter"
 msgstr "generera ett följebrev"
 
-#: builtin/log.c:1074
+#: builtin/log.c:1079
 msgid "use simple number sequence for output file names"
 msgstr "använd enkel nummersekvens för utdatafilnamn"
 
-#: builtin/log.c:1075
+#: builtin/log.c:1080
 msgid "sfx"
 msgstr "sfx"
 
-#: builtin/log.c:1076
+#: builtin/log.c:1081
 msgid "use <sfx> instead of '.patch'"
 msgstr "använd <sfx> istället för \".patch\""
 
-#: builtin/log.c:1078
+#: builtin/log.c:1083
 msgid "start numbering patches at <n> instead of 1"
 msgstr "börja numrera patchar på <n> istället för 1"
 
-#: builtin/log.c:1080
+#: builtin/log.c:1085
 msgid "Use [<prefix>] instead of [PATCH]"
 msgstr "Använd [<prefix>] istället för [PATCH]"
 
-#: builtin/log.c:1083
+#: builtin/log.c:1088
 msgid "store resulting files in <dir>"
 msgstr "spara filerna i <katalog>"
 
-#: builtin/log.c:1086
+#: builtin/log.c:1091
 msgid "don't strip/add [PATCH]"
 msgstr "ta inte bort eller lägg till [PATCH]"
 
-#: builtin/log.c:1089
+#: builtin/log.c:1094
 msgid "don't output binary diffs"
 msgstr "skriv inte binära diffar"
 
-#: builtin/log.c:1091
+#: builtin/log.c:1096
 msgid "don't include a patch matching a commit upstream"
 msgstr "ta inte med patchar som motsvarar en uppströmsincheckning"
 
-#: builtin/log.c:1093
+#: builtin/log.c:1098
 msgid "show patch format instead of default (patch + stat)"
 msgstr "visa patchformat istället för standard (patch + stat)"
 
-#: builtin/log.c:1095
+#: builtin/log.c:1100
 msgid "Messaging"
 msgstr "E-post"
 
-#: builtin/log.c:1096
+#: builtin/log.c:1101
 msgid "header"
 msgstr "huvud"
 
-#: builtin/log.c:1097
+#: builtin/log.c:1102
 msgid "add email header"
 msgstr "lägg till e-posthuvud"
 
-#: builtin/log.c:1098 builtin/log.c:1100
+#: builtin/log.c:1103 builtin/log.c:1105
 msgid "email"
 msgstr "epost"
 
-#: builtin/log.c:1098
+#: builtin/log.c:1103
 msgid "add To: header"
 msgstr "Lägg till mottagarhuvud (\"To:\")"
 
-#: builtin/log.c:1100
+#: builtin/log.c:1105
 msgid "add Cc: header"
 msgstr "Lägg till kopiehuvud (\"Cc:\")"
 
-#: builtin/log.c:1102
+#: builtin/log.c:1107
 msgid "message-id"
 msgstr "meddelande-id"
 
-#: builtin/log.c:1103
+#: builtin/log.c:1108
 msgid "make first mail a reply to <message-id>"
 msgstr "Gör det första brevet ett svar till <meddelande-id>"
 
-#: builtin/log.c:1104 builtin/log.c:1107
+#: builtin/log.c:1109 builtin/log.c:1112
 msgid "boundary"
 msgstr "gräns"
 
-#: builtin/log.c:1105
+#: builtin/log.c:1110
 msgid "attach the patch"
 msgstr "bifoga patchen"
 
-#: builtin/log.c:1108
+#: builtin/log.c:1113
 msgid "inline the patch"
 msgstr "gör patchen ett inline-objekt"
 
-#: builtin/log.c:1112
+#: builtin/log.c:1117
 msgid "enable message threading, styles: shallow, deep"
 msgstr "aktivera brevtrådning, typer: shallow, deep"
 
-#: builtin/log.c:1114
+#: builtin/log.c:1119
 msgid "signature"
 msgstr "signatur"
 
-#: builtin/log.c:1115
+#: builtin/log.c:1120
 msgid "add a signature"
 msgstr "lägg till signatur"
 
-#: builtin/log.c:1117
+#: builtin/log.c:1122
 msgid "don't print the patch filenames"
 msgstr "visa inte filnamn för patchar"
 
-#: builtin/log.c:1157
+#: builtin/log.c:1163
 #, c-format
 msgid "bogus committer info %s"
 msgstr "felaktig incheckarinformation %s"
 
-#: builtin/log.c:1202
+#: builtin/log.c:1208
 msgid "-n and -k are mutually exclusive."
 msgstr "-n och -k kan inte användas samtidigt."
 
-#: builtin/log.c:1204
+#: builtin/log.c:1210
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr "--subject-prefix och -k kan inte användas samtidigt."
 
-#: builtin/log.c:1212
+#: builtin/log.c:1218
 msgid "--name-only does not make sense"
 msgstr "kan inte använda --name-only"
 
-#: builtin/log.c:1214
+#: builtin/log.c:1220
 msgid "--name-status does not make sense"
 msgstr "kan inte använda --name-status"
 
-#: builtin/log.c:1216
+#: builtin/log.c:1222
 msgid "--check does not make sense"
 msgstr "kan inte använda --check"
 
-#: builtin/log.c:1239
+#: builtin/log.c:1245
 msgid "standard output, or directory, which one?"
 msgstr "standard ut, eller katalog, vilken skall det vara?"
 
-#: builtin/log.c:1241
+#: builtin/log.c:1247
 #, c-format
 msgid "Could not create directory '%s'"
 msgstr "Kunde inte skapa katalogen \"%s\""
 
-#: builtin/log.c:1394
+#: builtin/log.c:1400
 msgid "Failed to create output files"
 msgstr "Misslyckades skapa utdatafiler"
 
-#: builtin/log.c:1443
+#: builtin/log.c:1449
 msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
 msgstr "git cherry [-v] [<uppström> [<huvud> [<gräns>]]]"
 
-#: builtin/log.c:1498
+#: builtin/log.c:1504
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "Kunde inte hitta en spårad fjärrgren, ange <uppström> manuellt.\n"
 
-#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
+#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531
 #, c-format
 msgid "Unknown commit %s"
 msgstr "Okänd incheckning %s"
@@ -5767,37 +5809,33 @@ msgstr "Felaktig branch.%s.mergeoptions-sträng: %s"
 msgid "git write-tree failed to write a tree"
 msgstr "git write-tree misslyckades skriva ett träd"
 
-#: builtin/merge.c:678
-msgid "failed to read the cache"
-msgstr "misslyckads läsa cachen"
-
-#: builtin/merge.c:709
+#: builtin/merge.c:656
 msgid "Not handling anything other than two heads merge."
 msgstr "Hanterar inte något annat än en sammanslagning av två huvuden."
 
-#: builtin/merge.c:723
+#: builtin/merge.c:670
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr "Felaktig flagga för merge-recursive: -X%s"
 
-#: builtin/merge.c:737
+#: builtin/merge.c:684
 #, c-format
 msgid "unable to write %s"
 msgstr "kunde inte skriva %s"
 
-#: builtin/merge.c:876
+#: builtin/merge.c:773
 #, c-format
 msgid "Could not read from '%s'"
 msgstr "Kunde inte läsa från \"%s\""
 
-#: builtin/merge.c:885
+#: builtin/merge.c:782
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
 "Checkar inte in sammanslagningen; använd \"git commit\" för att slutföra "
 "den.\n"
 
-#: builtin/merge.c:891
+#: builtin/merge.c:788
 msgid ""
 "Please enter a commit message to explain why this merge is necessary,\n"
 "especially if it merges an updated upstream into a topic branch.\n"
@@ -5812,53 +5850,53 @@ msgstr ""
 "Rader som inleds med \"#\" kommer ignoreras, och ett tomt meddelande\n"
 "avbryter incheckningen.\n"
 
-#: builtin/merge.c:915
+#: builtin/merge.c:812
 msgid "Empty commit message."
 msgstr "Tomt incheckningsmeddelande."
 
-#: builtin/merge.c:927
+#: builtin/merge.c:824
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Underbart.\n"
 
-#: builtin/merge.c:992
+#: builtin/merge.c:889
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
 "Kunde inte slå ihop automatiskt; fixa konflikter och checka in resultatet.\n"
 
-#: builtin/merge.c:1008
+#: builtin/merge.c:905
 #, c-format
 msgid "'%s' is not a commit"
 msgstr "\"%s\" är inte en incheckning"
 
-#: builtin/merge.c:1049
+#: builtin/merge.c:946
 msgid "No current branch."
 msgstr "Inte på någon gren."
 
-#: builtin/merge.c:1051
+#: builtin/merge.c:948
 msgid "No remote for the current branch."
 msgstr "Ingen fjärr för aktuell gren."
 
-#: builtin/merge.c:1053
+#: builtin/merge.c:950
 msgid "No default upstream defined for the current branch."
 msgstr "Ingen standarduppström angiven för aktuell gren."
 
-#: builtin/merge.c:1058
+#: builtin/merge.c:955
 #, c-format
 msgid "No remote tracking branch for %s from %s"
 msgstr "Ingen fjärrspårande gren för %s från %s"
 
-#: builtin/merge.c:1145 builtin/merge.c:1302
+#: builtin/merge.c:1042 builtin/merge.c:1199
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - inte något vi kan slå ihop"
 
-#: builtin/merge.c:1213
+#: builtin/merge.c:1110
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "Det finns ingen sammanslagning att avbryta (MERGE_HEAD saknas)."
 
-#: builtin/merge.c:1229 git-pull.sh:31
+#: builtin/merge.c:1126 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -5866,11 +5904,11 @@ msgstr ""
 "Du har inte avslutat sammanslagningen (MERGE_HEAD finns).\n"
 "Checka in dina ändringar innan du kan slå ihop."
 
-#: builtin/merge.c:1232 git-pull.sh:34
+#: builtin/merge.c:1129 git-pull.sh:34
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)."
 
-#: builtin/merge.c:1236
+#: builtin/merge.c:1133
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -5878,79 +5916,79 @@ msgstr ""
 "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns).\n"
 "Checka in dina ändringar innan du kan slå ihop."
 
-#: builtin/merge.c:1239
+#: builtin/merge.c:1136
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns)."
 
-#: builtin/merge.c:1248
+#: builtin/merge.c:1145
 msgid "You cannot combine --squash with --no-ff."
 msgstr "Du kan inte kombinera --squash med --no-ff."
 
-#: builtin/merge.c:1253
+#: builtin/merge.c:1150
 msgid "You cannot combine --no-ff with --ff-only."
 msgstr "Du kan inte kombinera --no-ff med --ff-only."
 
-#: builtin/merge.c:1260
+#: builtin/merge.c:1157
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt."
 
-#: builtin/merge.c:1292
+#: builtin/merge.c:1189
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Kan endast slå ihop en enda incheckning i ett tomt huvud."
 
-#: builtin/merge.c:1295
+#: builtin/merge.c:1192
 msgid "Squash commit into empty head not supported yet"
 msgstr "Stöder inte en tillplattningsincheckning på ett tomt huvud ännu"
 
-#: builtin/merge.c:1297
+#: builtin/merge.c:1194
 msgid "Non-fast-forward commit does not make sense into an empty head"
 msgstr "Icke-snabbspolad incheckning kan inte användas med ett tomt huvud"
 
-#: builtin/merge.c:1412
+#: builtin/merge.c:1309
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Uppdaterar %s..%s\n"
 
-#: builtin/merge.c:1450
+#: builtin/merge.c:1348
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Försöker riktigt enkel sammanslagning i indexet...\n"
 
-#: builtin/merge.c:1457
+#: builtin/merge.c:1355
 #, c-format
 msgid "Nope.\n"
 msgstr "Nej.\n"
 
-#: builtin/merge.c:1489
+#: builtin/merge.c:1387
 msgid "Not possible to fast-forward, aborting."
 msgstr "Kan inte snabbspola, avbryter."
 
-#: builtin/merge.c:1512 builtin/merge.c:1591
+#: builtin/merge.c:1410 builtin/merge.c:1489
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Återspolar trädet till orört...\n"
 
-#: builtin/merge.c:1516
+#: builtin/merge.c:1414
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "Försöker sammanslagninsstrategin %s...\n"
 
-#: builtin/merge.c:1582
+#: builtin/merge.c:1480
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n"
 
-#: builtin/merge.c:1584
+#: builtin/merge.c:1482
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr "Sammanslagning med strategin %s misslyckades.\n"
 
-#: builtin/merge.c:1593
+#: builtin/merge.c:1491
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
 msgstr "Använder %s för att förbereda lösning för hand.\n"
 
-#: builtin/merge.c:1605
+#: builtin/merge.c:1503
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
@@ -6519,143 +6557,143 @@ msgstr "git pack-objects [flaggor...] basnamn [< reflista | < objektlista]"
 msgid "deflate error (%d)"
 msgstr "fel i deflate (%d)"
 
-#: builtin/pack-objects.c:2398
+#: builtin/pack-objects.c:2397
 #, c-format
 msgid "unsupported index version %s"
 msgstr "indexversionen %s stöds ej"
 
-#: builtin/pack-objects.c:2402
+#: builtin/pack-objects.c:2401
 #, c-format
 msgid "bad index version '%s'"
 msgstr "felaktig indexversion \"%s\""
 
-#: builtin/pack-objects.c:2425
+#: builtin/pack-objects.c:2424
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr "flaggan %s godtar inte negativ form"
 
-#: builtin/pack-objects.c:2429
+#: builtin/pack-objects.c:2428
 #, c-format
 msgid "unable to parse value '%s' for option %s"
 msgstr "kunde inte tolka värdet \"%s\" för flaggan %s"
 
-#: builtin/pack-objects.c:2448
+#: builtin/pack-objects.c:2447
 msgid "do not show progress meter"
 msgstr "visa inte förloppsindikator"
 
-#: builtin/pack-objects.c:2450
+#: builtin/pack-objects.c:2449
 msgid "show progress meter"
 msgstr "visa förloppsindikator"
 
-#: builtin/pack-objects.c:2452
+#: builtin/pack-objects.c:2451
 msgid "show progress meter during object writing phase"
 msgstr "visa förloppsindikator under objektskrivningsfasen"
 
-#: builtin/pack-objects.c:2455
+#: builtin/pack-objects.c:2454
 msgid "similar to --all-progress when progress meter is shown"
 msgstr "som --all-progress när förloppsmätaren visas"
 
-#: builtin/pack-objects.c:2456
+#: builtin/pack-objects.c:2455
 msgid "version[,offset]"
 msgstr "version[,offset]"
 
-#: builtin/pack-objects.c:2457
+#: builtin/pack-objects.c:2456
 msgid "write the pack index file in the specified idx format version"
 msgstr "skriv paketindexfilen i angiven indexformatversion"
 
-#: builtin/pack-objects.c:2460
+#: builtin/pack-objects.c:2459
 msgid "maximum size of each output pack file"
 msgstr "maximal storlek på varje utdatapaketfil"
 
-#: builtin/pack-objects.c:2462
+#: builtin/pack-objects.c:2461
 msgid "ignore borrowed objects from alternate object store"
 msgstr "ignorera lånade objekt från alternativa objektlager"
 
-#: builtin/pack-objects.c:2464
+#: builtin/pack-objects.c:2463
 msgid "ignore packed objects"
 msgstr "ignorera packade objekt"
 
-#: builtin/pack-objects.c:2466
+#: builtin/pack-objects.c:2465
 msgid "limit pack window by objects"
 msgstr "begränsa paketfönster efter objekt"
 
-#: builtin/pack-objects.c:2468
+#: builtin/pack-objects.c:2467
 msgid "limit pack window by memory in addition to object limit"
 msgstr "begränsa paketfönster efter minne förutom objektgräns"
 
-#: builtin/pack-objects.c:2470
+#: builtin/pack-objects.c:2469
 msgid "maximum length of delta chain allowed in the resulting pack"
 msgstr "maximal längd på deltakedja tillåten i slutligt paket"
 
-#: builtin/pack-objects.c:2472
+#: builtin/pack-objects.c:2471
 msgid "reuse existing deltas"
 msgstr "återanvänd befintliga delta"
 
-#: builtin/pack-objects.c:2474
+#: builtin/pack-objects.c:2473
 msgid "reuse existing objects"
 msgstr "återanvänd befintliga objekt"
 
-#: builtin/pack-objects.c:2476
+#: builtin/pack-objects.c:2475
 msgid "use OFS_DELTA objects"
 msgstr "använd OFS_DELTA-objekt"
 
-#: builtin/pack-objects.c:2478
+#: builtin/pack-objects.c:2477
 msgid "use threads when searching for best delta matches"
 msgstr "använd trådar vid sökning efter bästa deltaträffar"
 
-#: builtin/pack-objects.c:2480
+#: builtin/pack-objects.c:2479
 msgid "do not create an empty pack output"
 msgstr "försök inte skapa tom paketutdata"
 
-#: builtin/pack-objects.c:2482
+#: builtin/pack-objects.c:2481
 msgid "read revision arguments from standard input"
 msgstr "läs revisionsargument från standard in"
 
-#: builtin/pack-objects.c:2484
+#: builtin/pack-objects.c:2483
 msgid "limit the objects to those that are not yet packed"
 msgstr "begränsa objekt till de som ännu inte packats"
 
-#: builtin/pack-objects.c:2487
+#: builtin/pack-objects.c:2486
 msgid "include objects reachable from any reference"
 msgstr "inkludera objekt som kan nås från någon referens"
 
-#: builtin/pack-objects.c:2490
+#: builtin/pack-objects.c:2489
 msgid "include objects referred by reflog entries"
 msgstr "inkludera objekt som refereras från referensloggposter"
 
-#: builtin/pack-objects.c:2493
+#: builtin/pack-objects.c:2492
 msgid "output pack to stdout"
 msgstr "skriv paket på standard ut"
 
-#: builtin/pack-objects.c:2495
+#: builtin/pack-objects.c:2494
 msgid "include tag objects that refer to objects to be packed"
 msgstr "inkludera taggobjekt som refererar objekt som skall packas"
 
-#: builtin/pack-objects.c:2497
+#: builtin/pack-objects.c:2496
 msgid "keep unreachable objects"
 msgstr "behåll onåbara objekt"
 
-#: builtin/pack-objects.c:2498 parse-options.h:141
+#: builtin/pack-objects.c:2497 parse-options.h:141
 msgid "time"
 msgstr "tid"
 
-#: builtin/pack-objects.c:2499
+#: builtin/pack-objects.c:2498
 msgid "unpack unreachable objects newer than <time>"
 msgstr "packa upp onåbara objekt nyare än <tid>"
 
-#: builtin/pack-objects.c:2502
+#: builtin/pack-objects.c:2501
 msgid "create thin packs"
 msgstr "skapa tunna paket"
 
-#: builtin/pack-objects.c:2504
+#: builtin/pack-objects.c:2503
 msgid "ignore packs that have companion .keep file"
 msgstr "ignorera paket som har tillhörande .keep-fil"
 
-#: builtin/pack-objects.c:2506
+#: builtin/pack-objects.c:2505
 msgid "pack compression level"
 msgstr "komprimeringsgrad för paket"
 
-#: builtin/pack-objects.c:2508
+#: builtin/pack-objects.c:2507
 msgid "do not hide commits by grafts"
 msgstr "göm inte incheckningar med ympningar (\"grafts\")"
 
@@ -7066,7 +7104,7 @@ msgstr "git remote rename <gammal> <ny>"
 msgid "git remote remove <name>"
 msgstr "git remote remove <namn>"
 
-#: builtin/remote.c:15
+#: builtin/remote.c:15 builtin/remote.c:42
 msgid "git remote set-head <name> (-a | -d | <branch>)"
 msgstr "git remote set-head <namn> (-a | -d | <gren>)"
 
@@ -7104,10 +7142,6 @@ msgstr "git remote set-url --delete <namn> <url>"
 msgid "git remote add [<options>] <name> <url>"
 msgstr "git remote add [<flaggor>] <namn> <url>"
 
-#: builtin/remote.c:42
-msgid "git remote set-head <name> (-a | -d | <branch>])"
-msgstr "git remote set-head <namn> (-a | -d | <gren>])"
-
 #: builtin/remote.c:47
 msgid "git remote set-branches <name> <branch>..."
 msgstr "git remote set-branches <namn> <gren>..."
@@ -7556,15 +7590,15 @@ msgstr "git replace -d <objekt>..."
 msgid "git replace -l [<pattern>]"
 msgstr "git replace -l [<mönster>]"
 
-#: builtin/replace.c:118
+#: builtin/replace.c:121
 msgid "list replace refs"
 msgstr "visa ersättningsreferenser"
 
-#: builtin/replace.c:119
+#: builtin/replace.c:122
 msgid "delete replace refs"
 msgstr "ta bort ersättningsreferenser"
 
-#: builtin/replace.c:120
+#: builtin/replace.c:123
 msgid "replace the ref if it exists"
 msgstr "ersätt referensen om den finns"
 
@@ -7810,11 +7844,21 @@ msgstr "\"revert\" misslyckades"
 msgid "cherry-pick failed"
 msgstr "\"cherry-pick\" misslyckades"
 
-#: builtin/rm.c:14
+#: builtin/rm.c:15
 msgid "git rm [options] [--] <file>..."
 msgstr "git rm [flaggor] [--] <fil>..."
 
-#: builtin/rm.c:109
+#: builtin/rm.c:64 builtin/rm.c:186
+#, c-format
+msgid ""
+"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+"undermodulen \"%s\" (eller en av dess undermoduler) använder en .git-"
+"katalog\n"
+"(använd \"rm -rf\" om du verkligen vill ta bort den och all dess historik)"
+
+#: builtin/rm.c:174
 #, c-format
 msgid ""
 "'%s' has staged content different from both the file and the HEAD\n"
@@ -7823,7 +7867,7 @@ msgstr ""
 "\"%s\" har köat ändringar som skiljer sig både från filen och HEAD\n"
 "(använd -f för att tvinga borttagning)"
 
-#: builtin/rm.c:115
+#: builtin/rm.c:180
 #, c-format
 msgid ""
 "'%s' has changes staged in the index\n"
@@ -7832,7 +7876,7 @@ msgstr ""
 "\"%s\" har köade ändringar i indexet\n"
 "(använd --cached för att behålla filen eller -f för att tvinga borttagning)"
 
-#: builtin/rm.c:119
+#: builtin/rm.c:191
 #, c-format
 msgid ""
 "'%s' has local modifications\n"
@@ -7841,32 +7885,32 @@ msgstr ""
 "\"%s\" har lokala ändringar\n"
 "(använd --cached för att behålla filen eller -f för att tvinga borttagning)"
 
-#: builtin/rm.c:134
+#: builtin/rm.c:207
 msgid "do not list removed files"
 msgstr "lista inte borttagna filer"
 
-#: builtin/rm.c:135
+#: builtin/rm.c:208
 msgid "only remove from the index"
 msgstr "ta bara bort från indexet"
 
-#: builtin/rm.c:136
+#: builtin/rm.c:209
 msgid "override the up-to-date check"
 msgstr "överstyr àjour-testet"
 
-#: builtin/rm.c:137
+#: builtin/rm.c:210
 msgid "allow recursive removal"
 msgstr "tillåt rekursiv borttagning"
 
-#: builtin/rm.c:139
+#: builtin/rm.c:212
 msgid "exit with a zero status even if nothing matched"
 msgstr "avsluta med nollstatus även om inget träffades"
 
-#: builtin/rm.c:194
+#: builtin/rm.c:283
 #, c-format
 msgid "not removing '%s' recursively without -r"
 msgstr "tar inte bort \"%s\" rekursivt utan -r"
 
-#: builtin/rm.c:230
+#: builtin/rm.c:322
 #, c-format
 msgid "git rm: unable to remove %s"
 msgstr "git rm: kan inte ta bort %s"
@@ -7993,35 +8037,35 @@ msgstr ""
 msgid "git show-ref --exclude-existing[=pattern] < ref-list"
 msgstr "git show-ref --exclude-existing[=mönster] < reflista"
 
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:165
 msgid "only show tags (can be combined with heads)"
 msgstr "visa endast taggar (kan kombineras med huvuden)"
 
-#: builtin/show-ref.c:183
+#: builtin/show-ref.c:166
 msgid "only show heads (can be combined with tags)"
 msgstr "visa endast huvuden (kan kombineras med taggar)"
 
-#: builtin/show-ref.c:184
+#: builtin/show-ref.c:167
 msgid "stricter reference checking, requires exact ref path"
 msgstr "striktare referenskontroll, kräver exakt referenssökväg"
 
-#: builtin/show-ref.c:187 builtin/show-ref.c:189
+#: builtin/show-ref.c:170 builtin/show-ref.c:172
 msgid "show the HEAD reference"
 msgstr "visa HEAD-referensen"
 
-#: builtin/show-ref.c:191
+#: builtin/show-ref.c:174
 msgid "dereference tags into object IDs"
 msgstr "avreferera taggar till objekt-id"
 
-#: builtin/show-ref.c:193
+#: builtin/show-ref.c:176
 msgid "only show SHA1 hash using <n> digits"
 msgstr "visa SHA1-hash endast med <n> siffror"
 
-#: builtin/show-ref.c:197
+#: builtin/show-ref.c:180
 msgid "do not print results to stdout (useful with --verify)"
 msgstr "visa inte resultat på standard ut (användbart med --verify)"
 
-#: builtin/show-ref.c:199
+#: builtin/show-ref.c:182
 msgid "show refs from stdin that aren't in local repository"
 msgstr "visa referenser från standard in som inte finns i lokalt arkiv"
 
@@ -8029,20 +8073,28 @@ msgstr "visa referenser från standard in som inte finns i lokalt arkiv"
 msgid "git symbolic-ref [options] name [ref]"
 msgstr "git symbolic-ref [flaggor] namn [ref]"
 
-#: builtin/symbolic-ref.c:38
+#: builtin/symbolic-ref.c:8
+msgid "git symbolic-ref -d [-q] name"
+msgstr "git symbolic-ref -d [-q] namn"
+
+#: builtin/symbolic-ref.c:40
 msgid "suppress error message for non-symbolic (detached) refs"
 msgstr ""
 "undertryck felmeddelanden för icke-symboliska (frånkopplade) referenser"
 
-#: builtin/symbolic-ref.c:39
+#: builtin/symbolic-ref.c:41
+msgid "delete symbolic ref"
+msgstr "ta bort symbolisk referens"
+
+#: builtin/symbolic-ref.c:42
 msgid "shorten ref output"
 msgstr "förkorta ref-utdata"
 
-#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
 msgid "reason"
 msgstr "skäl"
 
-#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
 msgid "reason of the update"
 msgstr "skäl till uppdateringen"
 
@@ -8266,111 +8318,111 @@ msgstr "Uppdaterad tagg \"%s\" (var %s)\n"
 msgid "git update-index [options] [--] [<file>...]"
 msgstr "git update-index [flaggor] [--] [<fil>...]"
 
-#: builtin/update-index.c:717
+#: builtin/update-index.c:718
 msgid "continue refresh even when index needs update"
 msgstr "fortsätt uppdatera även när index inte är àjour"
 
-#: builtin/update-index.c:720
+#: builtin/update-index.c:721
 msgid "refresh: ignore submodules"
 msgstr "refresh: ignorera undermoduler"
 
-#: builtin/update-index.c:723
+#: builtin/update-index.c:724
 msgid "do not ignore new files"
 msgstr "ignorera inte nya filer"
 
-#: builtin/update-index.c:725
+#: builtin/update-index.c:726
 msgid "let files replace directories and vice-versa"
 msgstr "låt filer ersätta kataloger och omvänt"
 
-#: builtin/update-index.c:727
+#: builtin/update-index.c:728
 msgid "notice files missing from worktree"
 msgstr "lägg märke till filer som saknas i arbetskatalogen"
 
-#: builtin/update-index.c:729
+#: builtin/update-index.c:730
 msgid "refresh even if index contains unmerged entries"
 msgstr "uppdatera även om indexet innehåller ej sammanslagna poster"
 
-#: builtin/update-index.c:732
+#: builtin/update-index.c:733
 msgid "refresh stat information"
 msgstr "uppdatera statusinformation"
 
-#: builtin/update-index.c:736
+#: builtin/update-index.c:737
 msgid "like --refresh, but ignore assume-unchanged setting"
 msgstr "som --refresh, men ignorera assume-unchanged-inställning"
 
-#: builtin/update-index.c:740
+#: builtin/update-index.c:741
 msgid "<mode> <object> <path>"
 msgstr "<läge> <objekt> <sökväg>"
 
-#: builtin/update-index.c:741
+#: builtin/update-index.c:742
 msgid "add the specified entry to the index"
 msgstr "lägg till angiven post i indexet"
 
-#: builtin/update-index.c:745
+#: builtin/update-index.c:746
 msgid "(+/-)x"
 msgstr "(+/-)x"
 
-#: builtin/update-index.c:746
+#: builtin/update-index.c:747
 msgid "override the executable bit of the listed files"
 msgstr "överstyr exekveringsbiten för angivna filer"
 
-#: builtin/update-index.c:750
+#: builtin/update-index.c:751
 msgid "mark files as \"not changing\""
 msgstr "markera filer som \"ändras inte\""
 
-#: builtin/update-index.c:753
+#: builtin/update-index.c:754
 msgid "clear assumed-unchanged bit"
 msgstr "rensa \"assume-unchanged\"-biten"
 
-#: builtin/update-index.c:756
+#: builtin/update-index.c:757
 msgid "mark files as \"index-only\""
 msgstr "markera filer som \"endast index\""
 
-#: builtin/update-index.c:759
+#: builtin/update-index.c:760
 msgid "clear skip-worktree bit"
 msgstr "töm \"skip-worktree\"-biten"
 
-#: builtin/update-index.c:762
+#: builtin/update-index.c:763
 msgid "add to index only; do not add content to object database"
 msgstr "lägg endast till indexet; lägg inte till innehållet i objektdatabasen"
 
-#: builtin/update-index.c:764
+#: builtin/update-index.c:765
 msgid "remove named paths even if present in worktree"
 msgstr "ta bort namngivna sökvägar även om de finns i arbetskatalogen"
 
-#: builtin/update-index.c:766
+#: builtin/update-index.c:767
 msgid "with --stdin: input lines are terminated by null bytes"
 msgstr "med --stdin: indatarader termineras med null-byte"
 
-#: builtin/update-index.c:768
+#: builtin/update-index.c:769
 msgid "read list of paths to be updated from standard input"
 msgstr "läs lista över sökvägar att uppdatera från standard in"
 
-#: builtin/update-index.c:772
+#: builtin/update-index.c:773
 msgid "add entries from standard input to the index"
 msgstr "lägg poster från från standard in till indexet"
 
-#: builtin/update-index.c:776
+#: builtin/update-index.c:777
 msgid "repopulate stages #2 and #3 for the listed paths"
 msgstr "återfyll etapp 2 och 3 från angivna sökvägar"
 
-#: builtin/update-index.c:780
+#: builtin/update-index.c:781
 msgid "only update entries that differ from HEAD"
 msgstr "uppdatera endast poster som skiljer sig från HEAD"
 
-#: builtin/update-index.c:784
+#: builtin/update-index.c:785
 msgid "ignore files missing from worktree"
 msgstr "ignorera filer som saknas i arbetskatalogen"
 
-#: builtin/update-index.c:787
+#: builtin/update-index.c:788
 msgid "report actions to standard output"
 msgstr "raportera åtgärder på standard ut"
 
-#: builtin/update-index.c:789
+#: builtin/update-index.c:790
 msgid "(for porcelains) forget saved unresolved conflicts"
 msgstr "(för porslin) glöm sparade olösta konflikter"
 
-#: builtin/update-index.c:793
+#: builtin/update-index.c:794
 msgid "write index in this format"
 msgstr "skriv index i detta format"
 
@@ -8888,7 +8940,7 @@ msgstr "uppdaterar en ofödd gren med ändringar som lagts till i indexet"
 #. The working tree and the index file is still based on the
 #. $orig_head commit, but we are merging into $curr_head.
 #. First update the working tree to match $curr_head.
-#: git-pull.sh:228
+#: git-pull.sh:229
 #, sh-format
 msgid ""
 "Warning: fetch updated the current branch head.\n"
@@ -8899,11 +8951,11 @@ msgstr ""
 "Varning: snabbspolar din arbetskatalog från\n"
 "Varning: incheckningen $orig_head."
 
-#: git-pull.sh:253
+#: git-pull.sh:254
 msgid "Cannot merge multiple branches into empty head"
 msgstr "Kan inte slå ihop flera grenar i ett tomt huvud."
 
-#: git-pull.sh:257
+#: git-pull.sh:258
 msgid "Cannot rebase onto multiple branches"
 msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar"
 
@@ -9160,12 +9212,12 @@ msgstr "Inget grennamn angavs"
 msgid "(To restore them type \"git stash apply\")"
 msgstr "(För att återställa dem, skriv \"git stash apply\")"
 
-#: git-submodule.sh:88
+#: git-submodule.sh:89
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
 msgstr "kan inte ta bort en komponent från url:en \"$remoteurl\""
 
-#: git-submodule.sh:167
+#: git-submodule.sh:168
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
@@ -9181,17 +9233,17 @@ msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$sm_path\""
 msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
 msgstr "Gitkatalog \"$a\" ingår i underkatalogsökvägen \"$b\" eller omvänt"
 
-#: git-submodule.sh:312
+#: git-submodule.sh:316
 #, sh-format
 msgid "repo URL: '$repo' must be absolute or begin with ./|../"
 msgstr "arkiv-URL: \"$repo\" måste vara absolut eller börja med ./|../"
 
-#: git-submodule.sh:329
+#: git-submodule.sh:333
 #, sh-format
 msgid "'$sm_path' already exists in the index"
 msgstr "\"$sm_path\" finns redan i indexet"
 
-#: git-submodule.sh:333
+#: git-submodule.sh:337
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -9202,64 +9254,98 @@ msgstr ""
 "$sm_path\n"
 "Använd -f om du verkligen vill lägga till den"
 
-#: git-submodule.sh:344
+#: git-submodule.sh:355
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
 msgstr "Lägger till befintligt arkiv i \"$sm_path\" i indexet"
 
-#: git-submodule.sh:346
+#: git-submodule.sh:357
 #, sh-format
 msgid "'$sm_path' already exists and is not a valid git repo"
 msgstr "\"$sm_path\" finns redan och är inte ett giltigt git-arkiv"
 
-#: git-submodule.sh:360
+#: git-submodule.sh:365
+#, sh-format
+msgid "A git directory for '$sm_name' is found locally with remote(s):"
+msgstr "En git-katalog för \"$sm_name\" hittades lokalt med fjärr(ar):"
+
+#: git-submodule.sh:367
+#, sh-format
+msgid ""
+"If you want to reuse this local git directory instead of cloning again from"
+msgstr ""
+"För att återanvända den lokala git-katalogen istället för att på nytt klona "
+"från"
+
+#: git-submodule.sh:369
+#, sh-format
+msgid ""
+"use the '--force' option. If the local git directory is not the correct repo"
+msgstr ""
+"använd flaggan \"--force\". Om den lokala git-katalogen inte är riktigt arkiv"
+
+#: git-submodule.sh:370
+#, sh-format
+msgid ""
+"or you are unsure what this means choose another name with the '--name' "
+"option."
+msgstr ""
+"eller om du är osäker på vad det innebär, välj nytt namn med flaggan \"--name"
+"\"."
+
+#: git-submodule.sh:372
+#, sh-format
+msgid "Reactivating local git directory for submodule '$sm_name'."
+msgstr "Aktiverar lokal git-katalog för undermodulen \"$sm_name\" på nytt."
+
+#: git-submodule.sh:384
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Kan inte checka ut undermodulen \"$sm_path\""
 
-#: git-submodule.sh:365
+#: git-submodule.sh:389
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
 msgstr "Misslyckades lägga till undermodulen \"$sm_path\""
 
-#: git-submodule.sh:370
+#: git-submodule.sh:394
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
 msgstr "Misslyckades registrera undermodulen \"$sm_path\""
 
-#: git-submodule.sh:413
+#: git-submodule.sh:437
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
 msgstr "Går in i \"$prefix$sm_path\""
 
-#: git-submodule.sh:427
+#: git-submodule.sh:451
 #, sh-format
 msgid "Stopping at '$sm_path'; script returned non-zero status."
 msgstr ""
 "Stoppar på \"$sm_path\"; skriptet returnerade en status skild från noll."
 
-#: git-submodule.sh:471
+#: git-submodule.sh:495
 #, sh-format
 msgid "No url found for submodule path '$sm_path' in .gitmodules"
 msgstr "Hittade ingen url för undermodulsökvägen \"$sm_path\" i .gitmodules"
 
-#: git-submodule.sh:480
+#: git-submodule.sh:504
 #, sh-format
 msgid "Failed to register url for submodule path '$sm_path'"
 msgstr "Misslyckades registrera url för underkatalogsökväg \"$sm_path\""
 
-#: git-submodule.sh:482
+#: git-submodule.sh:506
 #, sh-format
 msgid "Submodule '$name' ($url) registered for path '$sm_path'"
 msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$sm_path\""
 
-#: git-submodule.sh:490
+#: git-submodule.sh:514
 #, sh-format
 msgid "Failed to register update mode for submodule path '$sm_path'"
 msgstr ""
 "Misslyckades registrera uppdateringsläge för undermodulsökväg \"$sm_path\""
 
-#: git-submodule.sh:590
+#: git-submodule.sh:614
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
@@ -9268,92 +9354,95 @@ msgstr ""
 "Undermodulen \"$sm_path\" har inte initierats\n"
 "Kanske du vill köra \"update --init\"?"
 
-#: git-submodule.sh:603
+#: git-submodule.sh:627
 #, sh-format
 msgid "Unable to find current revision in submodule path '$sm_path'"
 msgstr "Kan inte hitta aktuell revision i undermodulsökväg \"$sm_path\""
 
-#: git-submodule.sh:622
+#: git-submodule.sh:646
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr "Kan inte hämta i undermodulsökväg \"$sm_path\""
 
-#: git-submodule.sh:636
+#: git-submodule.sh:660
 #, sh-format
 msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
 msgstr "Kan inte ombasera \"$sha1\" i undermodulsökväg \"$sm_path\""
 
-#: git-submodule.sh:637
+#: git-submodule.sh:661
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
 msgstr "Undermodulsökvägen \"$sm_path\": ombaserade in i \"$sha1\""
 
-#: git-submodule.sh:642
+#: git-submodule.sh:666
 #, sh-format
 msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
 msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$sm_path\""
 
-#: git-submodule.sh:643
+#: git-submodule.sh:667
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
 msgstr "Undermodulsökvägen \"$sm_path\": sammanslagen i \"$sha1\""
 
-#: git-submodule.sh:648
+#: git-submodule.sh:672
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
 msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$sm_path\""
 
-#: git-submodule.sh:649
+#: git-submodule.sh:673
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
 msgstr "Undermodulsökvägen \"$sm_path\": checkade ut \"$sha1\""
 
-#: git-submodule.sh:671 git-submodule.sh:995
+#: git-submodule.sh:695 git-submodule.sh:1017
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
 msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\""
 
-#: git-submodule.sh:779
+#: git-submodule.sh:803
 msgid "The --cached option cannot be used with the --files option"
 msgstr "Flaggan --cached kan inte användas med flaggan --files"
 
 #. unexpected type
-#: git-submodule.sh:819
+#: git-submodule.sh:843
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "oväntat läge $mod_dst"
 
-#: git-submodule.sh:837
+#: git-submodule.sh:861
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr "  Varning: $name innehåller inte incheckning $sha1_src"
 
-#: git-submodule.sh:840
+#: git-submodule.sh:864
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr "  Varning: $name innehåller inte incheckning $sha1_dst"
 
-#: git-submodule.sh:843
+#: git-submodule.sh:867
 #, sh-format
 msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 msgstr "  Varning: $name innehåller inte incheckningar $sha1_src och $sha1_dst"
 
-#: git-submodule.sh:868
+#: git-submodule.sh:892
 msgid "blob"
 msgstr "blob"
 
-#: git-submodule.sh:906
+#: git-submodule.sh:930
 msgid "# Submodules changed but not updated:"
 msgstr "# Undermoduler ändrade men inte uppdaterade:"
 
-#: git-submodule.sh:908
+#: git-submodule.sh:932
 msgid "# Submodule changes to be committed:"
 msgstr "# Undermodulers ändringar att checka in:"
 
-#: git-submodule.sh:1054
+#: git-submodule.sh:1080
 #, sh-format
-msgid "Synchronizing submodule url for '$name'"
-msgstr "Synkroniserar undermodul-url för \"$name\""
+msgid "Synchronizing submodule url for '$prefix$sm_path'"
+msgstr "Synkroniserar undermodul-url för \"$prefix$sm_path\""
+
+#~ msgid "git remote set-head <name> (-a | -d | <branch>])"
+#~ msgstr "git remote set-head <namn> (-a | -d | <gren>])"
 
 #~ msgid " 0 files changed"
 #~ msgstr " 0 filer ändrade"
index ca617a3..2ccdf86 100644 (file)
--- a/po/vi.po
+++ b/po/vi.po
@@ -6,10 +6,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git-v1.8.0-rc2-4-g42e55\n"
+"Project-Id-Version: git-v1.8.0.1-347-gf94c3\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-10-16 08:38+0800\n"
-"PO-Revision-Date: 2012-10-17 08:09+0700\n"
+"POT-Creation-Date: 2012-11-30 12:40+0800\n"
+"PO-Revision-Date: 2012-11-30 13:40+0700\n"
 "Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
 "Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
 "Language: vi\n"
@@ -37,9 +37,9 @@ msgid ""
 "or use 'git commit -a'."
 msgstr ""
 "Sửa chúng trong cây làm việc,\n"
-"và sau đó dùng lệnh `git add/rm <tập-tin>'\n"
-"dành riêng cho việc đánh dấu cần giải quyết và tạo lần chuyển giao,\n"
-"hoặc là dùng lệnh `git commit -a'."
+"và sau đó dùng lệnh “git add/rm <tập-tin>” dành riêng\n"
+"cho việc đánh dấu tập tin cần giải quyết và tạo lần chuyển giao,\n"
+"hoặc là dùng lệnh “git commit -a”."
 
 #: archive.c:10
 msgid "git archive [options] <tree-ish> [<path>...]"
@@ -68,7 +68,7 @@ msgstr "fmt"
 msgid "archive format"
 msgstr "định dạng lưu trữ"
 
-#: archive.c:323 builtin/log.c:1079
+#: archive.c:323 builtin/log.c:1084
 msgid "prefix"
 msgstr "tiền tố"
 
@@ -76,9 +76,9 @@ msgstr "tiền tố"
 msgid "prepend prefix to each pathname in the archive"
 msgstr "nối thêm tiền tố vào từng đường dẫn tập tin trong kho lưu"
 
-#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2389
-#: builtin/blame.c:2390 builtin/config.c:56 builtin/fast-export.c:642
-#: builtin/fast-export.c:644 builtin/grep.c:801 builtin/hash-object.c:77
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390
+#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77
 #: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540
 #: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149
 msgid "file"
@@ -98,7 +98,7 @@ msgstr "liệt kê các tập tin được lưu trữ vào stderr (đầu ra l
 
 #: archive.c:330
 msgid "store only"
-msgstr "chỉ lưu"
+msgstr "chỉ lưu (không nén)"
 
 #: archive.c:331
 msgid "compress faster"
@@ -110,7 +110,7 @@ msgstr "nén nhỏ hơn"
 
 #: archive.c:342
 msgid "list supported archive formats"
-msgstr "liệt kê các kiểu né được hỗ trợ"
+msgstr "liệt kê các kiểu nén được hỗ trợ"
 
 #: archive.c:344 builtin/archive.c:93 builtin/clone.c:85
 msgid "repo"
@@ -128,30 +128,38 @@ msgstr "lệnh"
 msgid "path to the remote git-upload-archive command"
 msgstr "đường dẫn đến lệnh git-upload-pack trên máy chủ"
 
+#: attr.c:259
+msgid ""
+"Negative patterns are forbidden in git attributes\n"
+"Use '\\!' for literal leading exclamation."
+msgstr ""
+"Mấu dạng phủ định bị cấm chỉ dùng trong các thuộc tính của git\n"
+"Dùng '\\!' cho các chuỗi văn bản có dấu chấm than."
+
 #: bundle.c:36
 #, c-format
 msgid "'%s' does not look like a v2 bundle file"
-msgstr "`%s' không giống như tập tin v2 bundle (cụm)"
+msgstr "“%s” không giống như tập tin v2 bundle (định dạng dump của git)"
 
 #: bundle.c:63
 #, c-format
 msgid "unrecognized header: %s%s (%d)"
 msgstr "phần đầu (header) không được thừa nhận: %s%s (%d)"
 
-#: bundle.c:89 builtin/commit.c:672
+#: bundle.c:89 builtin/commit.c:674
 #, c-format
 msgid "could not open '%s'"
-msgstr "không thể mở `%s'"
+msgstr "không thể mở “%s”"
 
 #: bundle.c:140
 msgid "Repository lacks these prerequisite commits:"
 msgstr "Khó chứa thiếu những lần chuyển giao (commit) cần trước hết này:"
 
 #: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290
-#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
+#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
-msgstr "Cài đặt việc di chuyển qua các điểm xét lại gặp lỗi"
+msgstr "cài đặt việc di chuyển qua các điểm xét lại gặp lỗi"
 
 #: bundle.c:186
 #, c-format
@@ -173,9 +181,9 @@ msgstr[1] "Lệnh bundle yêu cầu %d tham chiếu (refs) này"
 
 #: bundle.c:294
 msgid "rev-list died"
-msgstr "rev-list bị chết"
+msgstr "rev-list đã chết"
 
-#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284
+#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284
 #, c-format
 msgid "unrecognized argument: %s"
 msgstr "đối số không được thừa nhận: %s"
@@ -183,7 +191,7 @@ msgstr "đối số không được thừa nhận: %s"
 #: bundle.c:335
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
-msgstr "tham chiếu `%s' bị loại trừ bởi các tùy chọn rev-list"
+msgstr "th.chiếu “%s” bị loại trừ bởi các tùy chọn rev-list"
 
 #: bundle.c:380
 msgid "Refusing to create empty bundle."
@@ -200,7 +208,7 @@ msgstr "pack-objects đã chết"
 #: bundle.c:419
 #, c-format
 msgid "cannot create '%s'"
-msgstr "không thể tạo `%s'"
+msgstr "không thể tạo “%s”"
 
 #: bundle.c:441
 msgid "index-pack died"
@@ -218,11 +226,11 @@ msgstr "%s %s không phải là một lần commit!"
 
 #: compat/obstack.c:406 compat/obstack.c:408
 msgid "memory exhausted"
-msgstr "cạn bộ nhớ"
+msgstr "hết bộ nhớ"
 
 #: connected.c:39
 msgid "Could not run 'git rev-list'"
-msgstr "Không thể chạy `git rev-list'"
+msgstr "Không thể chạy “git rev-list”"
 
 #: connected.c:48
 #, c-format
@@ -301,26 +309,31 @@ msgid_plural "%lu years ago"
 msgstr[0] "%lu năm trước"
 msgstr[1] "%lu năm trước"
 
-#: diff.c:105
+#: diff.c:111
+#, c-format
+msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
+msgstr "  Gặp lỗi khi phân tích dirstat cắt bỏ phần trăm '%s'\n"
+
+#: diff.c:116
 #, c-format
-msgid "  Failed to parse dirstat cut-off percentage '%.*s'\n"
-msgstr "  Gặp lỗi khi phân tích dirstat cắt bỏ phần trăm `%.*s'\n"
+msgid "  Unknown dirstat parameter '%s'\n"
+msgstr "  Không hiểu đối số dirstat '%s'\n"
 
-#: diff.c:110
+#: diff.c:194
 #, c-format
-msgid "  Unknown dirstat parameter '%.*s'\n"
-msgstr "  Không hiểu đối số dirstat `%.*s'\n"
+msgid "Unknown value for 'diff.submodule' config variable: '%s'"
+msgstr "Không hiểu giá trị cho biến cấu hình “diff.submodule”: `%s'"
 
-#: diff.c:210
+#: diff.c:237
 #, c-format
 msgid ""
 "Found errors in 'diff.dirstat' config variable:\n"
 "%s"
 msgstr ""
-"Tìm thấy các lỗi trong biến cấu hình 'diff.dirstat':\n"
+"Tìm thấy các lỗi trong biến cấu hình “diff.dirstat”:\n"
 "%s"
 
-#: diff.c:3458
+#: diff.c:3494
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -329,6 +342,11 @@ msgstr ""
 "Gặp lỗi khi phân tích đối số tùy chọn --dirstat/-X:\n"
 "%s"
 
+#: diff.c:3508
+#, c-format
+msgid "Failed to parse --submodule option parameter: '%s'"
+msgstr "Gặp lỗi khi phân tích đối số tùy chọn --submodule: `%s'"
+
 #: gpg-interface.c:59
 msgid "could not run gpg."
 msgstr "không thể chạy gpg."
@@ -341,25 +359,25 @@ msgstr "gpg đã không đồng ý dữ liệu"
 msgid "gpg failed to sign the data"
 msgstr "gpg gặp lỗi khi ký dữ liệu"
 
-#: grep.c:1441
+#: grep.c:1622
 #, c-format
 msgid "'%s': unable to read %s"
-msgstr "`%s': không thể đọc %s"
+msgstr "“%s”: không thể đọc %s"
 
-#: grep.c:1458
+#: grep.c:1639
 #, c-format
 msgid "'%s': %s"
-msgstr "`%s': %s"
+msgstr "“%s”: %s"
 
-#: grep.c:1469
+#: grep.c:1650
 #, c-format
 msgid "'%s': short read %s"
-msgstr "`%s': đọc ngắn %s"
+msgstr "“%s”: đọc ngắn %s"
 
 #: help.c:212
 #, c-format
 msgid "available git commands in '%s'"
-msgstr "các lệnh git sẵn sàng để dùng trong `%s'"
+msgstr "các lệnh git sẵn sàng để dùng trong “%s”"
 
 #: help.c:219
 msgid "git commands available from elsewhere on your $PATH"
@@ -371,7 +389,7 @@ msgid ""
 "'%s' appears to be a git command, but we were not\n"
 "able to execute it. Maybe git-%s is broken?"
 msgstr ""
-"`%s' trông như là một lệnh git, nhưng chúng tôi không\n"
+"“%s” trông như là một lệnh git, nhưng chúng tôi không\n"
 "thể thực thi nó. Có lẽ là lệnh git-%s đã bị hỏng?"
 
 #: help.c:332
@@ -384,8 +402,8 @@ msgid ""
 "WARNING: You called a Git command named '%s', which does not exist.\n"
 "Continuing under the assumption that you meant '%s'"
 msgstr ""
-"CẢNH BÁO: Bạn đã gọi lệnh Git có tên `%s', mà nó lại không có sẵn.\n"
-"Giả định rằng ý bạn là `%s'"
+"CẢNH BÁO: Bạn đã gọi lệnh Git có tên “%s”, mà nó lại không có sẵn.\n"
+"Giả định rằng ý bạn là “%s”"
 
 #: help.c:359
 #, c-format
@@ -395,7 +413,7 @@ msgstr "trong %0.1f giây một cách tự động..."
 #: help.c:366
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: `%s' không phải là một lệnh của git. Xem `git --help'."
+msgstr "git: “%s” không phải là một lệnh của git. Xem “git --help”."
 
 #: help.c:370
 msgid ""
@@ -411,6 +429,15 @@ msgstr[1] ""
 "\n"
 "Có phải ý bạn là một trong số những cái này không?"
 
+#: merge.c:56
+msgid "failed to read the cache"
+msgstr "gặp lỗi khi đọc bộ nhớ tạm"
+
+#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534
+#: builtin/clone.c:586
+msgid "unable to write new index file"
+msgstr "không thể ghi tập tin lưu bảng mục lục mới"
+
 #: merge-recursive.c:190
 #, c-format
 msgid "(bad commit)\n"
@@ -419,7 +446,7 @@ msgstr "(commit sai)\n"
 #: merge-recursive.c:206
 #, c-format
 msgid "addinfo_cache failed for path '%s'"
-msgstr "addinfo_cache gặp lỗi đối với đường dẫn `%s'"
+msgstr "addinfo_cache gặp lỗi đối với đường dẫn “%s”"
 
 #: merge-recursive.c:268
 msgid "error building trees"
@@ -428,7 +455,7 @@ msgstr "gặp lỗi khi xây dựng cây"
 #: merge-recursive.c:672
 #, c-format
 msgid "failed to create path '%s'%s"
-msgstr "gặp lỗi khi tạo đường dẫn `%s'%s"
+msgstr "gặp lỗi khi tạo đường dẫn “%s”%s"
 
 #: merge-recursive.c:683
 #, c-format
@@ -444,32 +471,32 @@ msgstr ": có lẽ là một xung đột D/F?"
 #: merge-recursive.c:708
 #, c-format
 msgid "refusing to lose untracked file at '%s'"
-msgstr "từ chối đóng tập tin không được theo vết tại `%s'"
+msgstr "từ chối đóng tập tin không được theo vết tại “%s”"
 
 #: merge-recursive.c:748
 #, c-format
 msgid "cannot read object %s '%s'"
-msgstr "không thể đọc đối tượng %s `%s'"
+msgstr "không thể đọc đối tượng %s “%s”"
 
 #: merge-recursive.c:750
 #, c-format
 msgid "blob expected for %s '%s'"
-msgstr "đối tượng blob được mong đợi cho %s `%s'"
+msgstr "đối tượng blob được mong đợi cho %s “%s”"
 
 #: merge-recursive.c:773 builtin/clone.c:302
 #, c-format
 msgid "failed to open '%s'"
-msgstr "gặp lỗi khi mở `%s'"
+msgstr "gặp lỗi khi mở “%s”"
 
 #: merge-recursive.c:781
 #, c-format
 msgid "failed to symlink '%s'"
-msgstr "gặp lỗi khi tạo liên kết tượng trưng (symlink) `%s'"
+msgstr "gặp lỗi khi tạo liên kết tượng trưng (symlink) “%s”"
 
 #: merge-recursive.c:784
 #, c-format
 msgid "do not know what to do with %06o %s '%s'"
-msgstr "không hiểu phải làm gì với %06o %s `%s'"
+msgstr "không hiểu phải làm gì với %06o %s “%s”"
 
 #: merge-recursive.c:922
 msgid "Failed to execute internal merge"
@@ -591,7 +618,7 @@ msgstr "Đã bỏ qua %s (đã có sẵn lần hòa trộn này)"
 msgid "Auto-merging %s"
 msgstr "Tự-động-hòa-trộn %s"
 
-#: merge-recursive.c:1633 git-submodule.sh:869
+#: merge-recursive.c:1633 git-submodule.sh:893
 msgid "submodule"
 msgstr "mô-đun-con"
 
@@ -661,9 +688,9 @@ msgstr "hòa trộn không trả về lần chuyển giao (commit) nào"
 #: merge-recursive.c:1997
 #, c-format
 msgid "Could not parse object '%s'"
-msgstr "Không thể phân tích đối tượng `%s'"
+msgstr "Không thể phân tích đối tượng “%s”"
 
-#: merge-recursive.c:2009 builtin/merge.c:696
+#: merge-recursive.c:2009 builtin/merge.c:643
 msgid "Unable to write index."
 msgstr "Không thể ghi bảng mục lục"
 
@@ -692,22 +719,30 @@ msgstr "    %s"
 #, c-format
 msgid "Your branch is ahead of '%s' by %d commit.\n"
 msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
-msgstr[0] "Nhánh của bạn là đầu của `%s' bởi %d lần chuyển giao (commit).\n"
-msgstr[1] "Nhánh của bạn là đầu của `%s' bởi %d lần chuyển giao (commit).\n"
+msgstr[0] "Nhánh của bạn là đầu của “%s” bởi %d lần chuyển giao (commit).\n"
+msgstr[1] "Nhánh của bạn là đầu của “%s” bởi %d lần chuyển giao (commit).\n"
+
+#: remote.c:1637
+msgid "  (use \"git push\" to publish your local commits)\n"
+msgstr "  (dùng \"git push\" để xuất bản các lần chuyển giao nội bộ của bạn)\n"
 
-#: remote.c:1638
+#: remote.c:1640
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
 "Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
 msgstr[0] ""
-"Nhánh của bạn thì ở đằng sau `%s' bởi %d lần chuyển giao (commit), và có thể "
+"Nhánh của bạn thì ở đằng sau “%s” bởi %d lần chuyển giao (commit), và có thể "
 "được fast-forward.\n"
 msgstr[1] ""
-"Nhánh của bạn thì ở đằng sau `%s' bởi %d lần chuyển giao (commit), và có thể "
+"Nhánh của bạn thì ở đằng sau “%s” bởi %d lần chuyển giao (commit), và có thể "
 "được fast-forward.\n"
 
-#: remote.c:1646
+#: remote.c:1647
+msgid "  (use \"git pull\" to update your local branch)\n"
+msgstr "  (dùng \"git pull\" để cập nhật nhánh nội bộ của bạn)\n"
+
+#: remote.c:1650
 #, c-format
 msgid ""
 "Your branch and '%s' have diverged,\n"
@@ -716,24 +751,30 @@ msgid_plural ""
 "Your branch and '%s' have diverged,\n"
 "and have %d and %d different commits each, respectively.\n"
 msgstr[0] ""
-"Nhánh của bạn và `%s' bị phân kỳ,\n"
+"Nhánh của bạn và “%s” bị phân kỳ,\n"
 "và có %d và %d lần chuyển giao (commit) khác nhau cho từng cái,\n"
 "tương ứng với mỗi lần.\n"
 msgstr[1] ""
-"Your branch and `%s' have diverged,\n"
+"Your branch and “%s” have diverged,\n"
 "and have %d and %d different commit each, respectively.\n"
 
-#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
-#: builtin/merge.c:1087 builtin/merge.c:1097
+#: remote.c:1659
+msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
+msgstr ""
+"  (dùng \"git pull\" để hòa trộn nhánh trên máy chủ vào trong nhánh của "
+"bạn)\n"
+
+#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984
+#: builtin/merge.c:994
 #, c-format
 msgid "Could not open '%s' for writing"
-msgstr "Không thể mở %s' để ghi"
+msgstr "Không thể mở “%s” để ghi"
 
-#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
-#: builtin/merge.c:1089 builtin/merge.c:1102
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986
+#: builtin/merge.c:999
 #, c-format
 msgid "Could not write to '%s'"
-msgstr "Không thể ghi vào `%s'"
+msgstr "Không thể ghi vào “%s”"
 
 #: sequencer.c:146
 msgid ""
@@ -741,7 +782,7 @@ msgid ""
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
 "sau khi giải quyết các xung đột, đánh dấu đường dẫn đã sửa\n"
-"với lệnh `git add <đường_dẫn>' hoặc `git rm <đường_dẫn>'"
+"với lệnh “git add <đường_dẫn>” hoặc “git rm <đường_dẫn>”"
 
 #: sequencer.c:149
 msgid ""
@@ -750,8 +791,8 @@ msgid ""
 "and commit the result with 'git commit'"
 msgstr ""
 "sau khi giải quyết các xung đột, đánh dấu đường dẫn đã sửa\n"
-"với lệnh `git add <đường_dẫn>' hoặc `git rm <đường_dẫn>'\n"
-"và chuyển giao (commit) kết quả bằng lệnh `git commit'"
+"với lệnh “git add <đường_dẫn>” hoặc “git rm <đường_dẫn>”\n"
+"và chuyển giao (commit) kết quả bằng lệnh “git commit”"
 
 #: sequencer.c:162 sequencer.c:770 sequencer.c:853
 #, c-format
@@ -953,7 +994,7 @@ msgstr "kết thúc tập tin đột xuất"
 #: sequencer.c:827
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
-msgstr "tập tin HEAD 'pre-cherry-pick' đã lưu `%s' bị hỏng"
+msgstr "tập tin HEAD “pre-cherry-pick” đã lưu “%s” bị hỏng"
 
 #: sequencer.c:850
 #, c-format
@@ -975,24 +1016,24 @@ msgstr "HEAD không chỉ đến một nhánh nào cả"
 #: sha1_name.c:1047
 #, c-format
 msgid "No such branch: '%s'"
-msgstr "Không có nhánh nào như thế: `%s'"
+msgstr "Không có nhánh nào như thế: “%s”"
 
 #: sha1_name.c:1049
 #, c-format
 msgid "No upstream configured for branch '%s'"
-msgstr "Không có thượng nguồn (upstream) được cấu hình cho nhánh `%s'"
+msgstr "Không có thượng nguồn (upstream) được cấu hình cho nhánh “%s”"
 
 #: sha1_name.c:1052
 #, c-format
 msgid "Upstream branch '%s' not stored as a remote-tracking branch"
 msgstr ""
-"Nhánh thượng nguồn (upstream) `%s' không được lưu lại như là một nhánh "
-"'remote-tracking'"
+"Nhánh thượng nguồn (upstream) “%s” không được lưu lại như là một nhánh "
+"“remote-tracking”"
 
 #: wrapper.c:408
 #, c-format
 msgid "unable to access '%s': %s"
-msgstr "không thể truy cập `%s': %s"
+msgstr "không thể truy cập “%s”: %s"
 
 #: wrapper.c:426
 #, c-format
@@ -1177,7 +1218,7 @@ msgstr "  (dùng \"git commit\" để hoàn tất việc hòa trộn)"
 
 #: wt-status.c:804
 msgid "You are in the middle of an am session."
-msgstr "Bạn đang ở giữa của một phiên 'am'."
+msgstr "Bạn đang ở giữa của một phiên “am”."
 
 #: wt-status.c:807
 msgid "The current patch is empty."
@@ -1379,34 +1420,34 @@ msgstr "git add [các-tùy-chọn] [--] <mẫu-tập-tin>..."
 msgid "unexpected diff status %c"
 msgstr "trạng thái lệnh diff không như mong đợi %c"
 
-#: builtin/add.c:67 builtin/commit.c:230
+#: builtin/add.c:67 builtin/commit.c:231
 msgid "updating files failed"
 msgstr "Cập nhật tập tin gặp lỗi"
 
 #: builtin/add.c:77
 #, c-format
 msgid "remove '%s'\n"
-msgstr "gỡ bỏ `%s'\n"
+msgstr "gỡ bỏ “%s”\n"
 
 #: builtin/add.c:176
 #, c-format
 msgid "Path '%s' is in submodule '%.*s'"
-msgstr "Đường dẫn `%s' thì ở trong mô-đun-con `%.*s'"
+msgstr "Đường dẫn “%s” thì ở trong mô-đun-con “%.*s”"
 
 #: builtin/add.c:192
 msgid "Unstaged changes after refreshing the index:"
 msgstr ""
 "Các thay đổi không được lưu trạng thái sau khi làm tươi mới lại bảng mục lục:"
 
-#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186
+#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275
 #, c-format
 msgid "pathspec '%s' did not match any files"
-msgstr "pathspec `%s' không khớp với bất kỳ tập tin nào"
+msgstr "pathspec “%s” không khớp với bất kỳ tập tin nào"
 
 #: builtin/add.c:209
 #, c-format
 msgid "'%s' is beyond a symbolic link"
-msgstr "`%s' nằm ngoài một liên kết tượng trưng"
+msgstr "“%s” nằm ngoài một liên kết tượng trưng"
 
 #: builtin/add.c:276
 msgid "Could not read the index"
@@ -1415,7 +1456,7 @@ msgstr "Không thể đọc bảng mục lục"
 #: builtin/add.c:286
 #, c-format
 msgid "Could not open '%s' for writing."
-msgstr "Không thể mở `%s' để ghi"
+msgstr "Không thể mở “%s” để ghi"
 
 #: builtin/add.c:290
 msgid "Could not write patch"
@@ -1424,7 +1465,7 @@ msgstr "Không thể ghi ra miếng vá"
 #: builtin/add.c:295
 #, c-format
 msgid "Could not stat '%s'"
-msgstr "không thể lấy trạng thái về `%s'"
+msgstr "không thể lấy trạng thái về “%s”"
 
 #: builtin/add.c:297
 msgid "Empty patch. Aborted."
@@ -1433,7 +1474,7 @@ msgstr "Miếng vá trống rỗng. Đã bỏ qua."
 #: builtin/add.c:303
 #, c-format
 msgid "Could not apply '%s'"
-msgstr "Không thể apply (áp dụng miếng vá) `%s'"
+msgstr "Không thể apply (áp dụng miếng vá) “%s”"
 
 #: builtin/add.c:313
 msgid "The following paths are ignored by one of your .gitignore files:\n"
@@ -1443,12 +1484,12 @@ msgstr ""
 
 #: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63
 #: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253
-#: builtin/rm.c:133
+#: builtin/rm.c:206
 msgid "dry run"
 msgstr "chạy thử"
 
-#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1154
-#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160
+#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483
 #: builtin/mv.c:62 builtin/read-tree.c:112
 msgid "be verbose"
 msgstr "chi tiết"
@@ -1457,9 +1498,9 @@ msgstr "chi tiết"
 msgid "interactive picking"
 msgstr "sửa bằng cách tương tác"
 
-#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248
+#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248
 msgid "select hunks interactively"
-msgstr "chọn `hunks' một cách tương tác"
+msgstr "chọn “hunks” một cách tương tác"
 
 #: builtin/add.c:324
 msgid "edit current diff and apply"
@@ -1525,14 +1566,14 @@ msgstr "Không có gì được chỉ ra, không có gì được thêm vào.\n"
 #: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
-msgstr "Có lẽ bạn muốn là `git add .' phải không?\n"
+msgstr "Có lẽ bạn muốn là “git add .” phải không?\n"
 
-#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
-#: builtin/rm.c:162
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82
+#: builtin/rm.c:235
 msgid "index file corrupt"
 msgstr "tập tin ghi bảng mục lục bị hỏng"
 
-#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260
+#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370
 msgid "Unable to write new index file"
 msgstr "Không thể ghi tập tin lưu bảng mục lục mới"
 
@@ -1543,12 +1584,12 @@ msgstr "git apply [các-tùy-chọn] [<miếng-vá>...]"
 #: builtin/apply.c:110
 #, c-format
 msgid "unrecognized whitespace option '%s'"
-msgstr "không nhận ra tùy chọn về khoảng trắng `%s'"
+msgstr "không nhận ra tùy chọn về khoảng trắng “%s”"
 
 #: builtin/apply.c:125
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
-msgstr "không nhận ra tùy chọn bỏ qua khoảng trắng `%s'"
+msgstr "không nhận ra tùy chọn bỏ qua khoảng trắng “%s”"
 
 #: builtin/apply.c:823
 #, c-format
@@ -1654,7 +1695,7 @@ msgstr "miếng vá định dạng nhị phân không được nhận ra tại d
 #: builtin/apply.c:1984
 #, c-format
 msgid "patch with only garbage at line %d"
-msgstr "vá chỉ với 'garbage' tại dòng %d"
+msgstr "vá chỉ với “garbage” tại dòng %d"
 
 #: builtin/apply.c:2074
 #, c-format
@@ -1673,7 +1714,7 @@ msgstr "ôi?"
 #: builtin/apply.c:2671
 #, c-format
 msgid "invalid start of line: '%c'"
-msgstr "sai khởi đầu dòng: `%c'"
+msgstr "sai khởi đầu dòng: “%c”"
 
 #: builtin/apply.c:2789
 #, c-format
@@ -1699,18 +1740,18 @@ msgstr ""
 #: builtin/apply.c:2826
 #, c-format
 msgid "missing binary patch data for '%s'"
-msgstr "thiếu dữ liệu của miếng vá định dạng nhị phân cho `%s'"
+msgstr "thiếu dữ liệu của miếng vá định dạng nhị phân cho “%s”"
 
 #: builtin/apply.c:2929
 #, c-format
 msgid "binary patch does not apply to '%s'"
-msgstr "miếng vá định dạng nhị phân không được áp dụng cho `%s'"
+msgstr "miếng vá định dạng nhị phân không được áp dụng cho “%s”"
 
 #: builtin/apply.c:2935
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
 msgstr ""
-"vá nhị phân cho `%s' tạo ra kết quả không chính xác (mong chờ %s, lại nhận "
+"vá nhị phân cho “%s” tạo ra kết quả không chính xác (mong chờ %s, lại nhận "
 "%s)"
 
 #: builtin/apply.c:2956
@@ -1795,7 +1836,7 @@ msgstr "Đang kiểm tra miếng vá %s..."
 #: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158
 #, c-format
 msgid "make_cache_entry failed for path '%s'"
-msgstr "make_cache_entry gặp lỗi đối với đường dẫn `%s'"
+msgstr "make_cache_entry gặp lỗi đối với đường dẫn “%s”"
 
 #: builtin/apply.c:3767
 #, c-format
@@ -1815,7 +1856,7 @@ msgstr "không thể lấy trạng thái về tập tin %s mới hơn đã đư
 #: builtin/apply.c:3804
 #, c-format
 msgid "unable to create backing store for newly created file %s"
-msgstr "không thể tạo 'backing store' cho tập tin được tạo mới hơn %s"
+msgstr "không thể tạo “backing store” cho tập tin được tạo mới hơn %s"
 
 #: builtin/apply.c:3807 builtin/apply.c:3915
 #, c-format
@@ -1825,12 +1866,12 @@ msgstr "không thể thêm mục nhớ tạm cho %s"
 #: builtin/apply.c:3840
 #, c-format
 msgid "closing file '%s'"
-msgstr "đang đóng tập tin `%s'"
+msgstr "đang đóng tập tin “%s”"
 
 #: builtin/apply.c:3889
 #, c-format
 msgid "unable to write file '%s' mode %o"
-msgstr "không thể ghi vào tập tin `%s' chế độ (mode) %o"
+msgstr "không thể ghi vào tập tin “%s” chế độ (mode) %o"
 
 #: builtin/apply.c:3976
 #, c-format
@@ -2005,7 +2046,7 @@ msgstr "--cached ở ngoài một kho chứa"
 #: builtin/apply.c:4411
 #, c-format
 msgid "can't open patch '%s'"
-msgstr "không thể mở miếng vá `%s'"
+msgstr "không thể mở miếng vá “%s”"
 
 #: builtin/apply.c:4425
 #, c-format
@@ -2024,7 +2065,7 @@ msgstr[1] "%d dòng thêm khoảng trắng lỗi."
 #: builtin/archive.c:17
 #, c-format
 msgid "could not create archive file '%s'"
-msgstr "không thể tạo tập tin kho (lưu trữ, nén) `%s'"
+msgstr "không thể tạo tập tin kho (lưu trữ, nén) “%s”"
 
 #: builtin/archive.c:20
 msgid "could not redirect output"
@@ -2062,7 +2103,7 @@ msgstr "git bisect--helper --next-all [--no-checkout]"
 
 #: builtin/bisect--helper.c:17
 msgid "perform 'git bisect next'"
-msgstr "thực hiện `git bisect next'"
+msgstr "thực hiện “git bisect next”"
 
 #: builtin/bisect--helper.c:19
 msgid "update BISECT_HEAD instead of checking out the current commit"
@@ -2078,97 +2119,97 @@ msgstr "git blame [các-tùy-chọn] [rev-opts] [rev] [--] tập-tin"
 msgid "[rev-opts] are documented in git-rev-list(1)"
 msgstr "[rev-opts] được mô tả trong git-rev-list(1)"
 
-#: builtin/blame.c:2373
+#: builtin/blame.c:2374
 msgid "Show blame entries as we find them, incrementally"
-msgstr "Hiển thị các mục `blame' như là chúng ta thấy chúng, tăng dần"
+msgstr "Hiển thị các mục “blame” như là chúng ta thấy chúng, tăng dần"
 
-#: builtin/blame.c:2374
+#: builtin/blame.c:2375
 msgid "Show blank SHA-1 for boundary commits (Default: off)"
 msgstr ""
-"Hiá»\83n thá»\8b SHA-1 trá»\91ng cho những lần chuyển giao biên giới (Mặc định: off)"
+"Hiá»\83n thá»\8b SHA-1 trắng cho những lần chuyển giao biên giới (Mặc định: off)"
 
-#: builtin/blame.c:2375
+#: builtin/blame.c:2376
 msgid "Do not treat root commits as boundaries (Default: off)"
 msgstr "Không coi các lần chuyển giao gốc là giới hạn (Mặc định: off)"
 
-#: builtin/blame.c:2376
+#: builtin/blame.c:2377
 msgid "Show work cost statistics"
 msgstr "Hiển thị thống kê công sức làm việc"
 
-#: builtin/blame.c:2377
+#: builtin/blame.c:2378
 msgid "Show output score for blame entries"
-msgstr "Hiển thị kết xuất điểm số có các mục tin `blame'"
+msgstr "Hiển thị kết xuất điểm số có các mục tin “blame”"
 
-#: builtin/blame.c:2378
+#: builtin/blame.c:2379
 msgid "Show original filename (Default: auto)"
 msgstr "Hiển thị tên tập tin gốc (Mặc định: auto)"
 
-#: builtin/blame.c:2379
+#: builtin/blame.c:2380
 msgid "Show original linenumber (Default: off)"
 msgstr "Hiển thị số dòng gốc (Mặc định: off)"
 
-#: builtin/blame.c:2380
+#: builtin/blame.c:2381
 msgid "Show in a format designed for machine consumption"
 msgstr "Hiển thị ở định dạng đã thiết kế cho sự tiêu dùng bằng máy"
 
-#: builtin/blame.c:2381
+#: builtin/blame.c:2382
 msgid "Show porcelain format with per-line commit information"
-msgstr "Hiển thị định dạng 'porcelain' với thông tin chuyển giao mỗi dòng"
+msgstr "Hiển thị định dạng “porcelain” với thông tin chuyển giao mỗi dòng"
 
-#: builtin/blame.c:2382
+#: builtin/blame.c:2383
 msgid "Use the same output mode as git-annotate (Default: off)"
 msgstr "Dùng cùng chế độ xuất ra vóigit-annotate (Mặc định: off)"
 
-#: builtin/blame.c:2383
+#: builtin/blame.c:2384
 msgid "Show raw timestamp (Default: off)"
 msgstr "Hiển thị dấu vết thời gian dạng thô (Mặc định: off)"
 
-#: builtin/blame.c:2384
+#: builtin/blame.c:2385
 msgid "Show long commit SHA1 (Default: off)"
 msgstr "Hiển thị SHA1 của lần chuyển giao (commit) dạng dài (Mặc định: off)"
 
-#: builtin/blame.c:2385
+#: builtin/blame.c:2386
 msgid "Suppress author name and timestamp (Default: off)"
 msgstr "Không hiển thị tên tác giả và dấu vết thời gian (Mặc định: off)"
 
-#: builtin/blame.c:2386
+#: builtin/blame.c:2387
 msgid "Show author email instead of name (Default: off)"
 msgstr "Hiển thị thư điện tử của tác giả thay vì tên (Mặc định: off)"
 
-#: builtin/blame.c:2387
+#: builtin/blame.c:2388
 msgid "Ignore whitespace differences"
 msgstr "Bỏ qua các khác biệt do khoảng trắng gây ra"
 
-#: builtin/blame.c:2388
+#: builtin/blame.c:2389
 msgid "Spend extra cycles to find better match"
 msgstr "Tiêu thụ thêm năng tài nguyên máy móc để tìm kiếm tốt hơn nữa"
 
-#: builtin/blame.c:2389
+#: builtin/blame.c:2390
 msgid "Use revisions from <file> instead of calling git-rev-list"
 msgstr ""
-"Sử dụng điểm xét duyệt (revision) từ <tập tin> thay vì gọi `git-rev-list'"
+"Sử dụng điểm xét duyệt (revision) từ <tập tin> thay vì gọi “git-rev-list”"
 
-#: builtin/blame.c:2390
+#: builtin/blame.c:2391
 msgid "Use <file>'s contents as the final image"
 msgstr "Sử dụng nội dung của <tập tin> như là ảnh cuối cùng"
 
-#: builtin/blame.c:2391 builtin/blame.c:2392
+#: builtin/blame.c:2392 builtin/blame.c:2393
 msgid "score"
 msgstr "điểm số"
 
-#: builtin/blame.c:2391
+#: builtin/blame.c:2392
 msgid "Find line copies within and across files"
 msgstr "Tìm các bản sao chép dòng trong và ngang qua tập tin"
 
-#: builtin/blame.c:2392
+#: builtin/blame.c:2393
 msgid "Find line movements within and across files"
 msgstr "Tìm các di chuyển dòng trong và ngang qua tập tin"
 
-#: builtin/blame.c:2393
+#: builtin/blame.c:2394
 msgid "n,m"
 msgstr "n,m"
 
-#: builtin/blame.c:2393
+#: builtin/blame.c:2394
 msgid "Process only line range n,m, counting from 1"
 msgstr "Xử lý chỉ dòng vùng n,m, tính từ 1"
 
@@ -2194,8 +2235,8 @@ msgid ""
 "deleting branch '%s' that has been merged to\n"
 "         '%s', but not yet merged to HEAD."
 msgstr ""
-"đang xóa nhánh `%s' mà nó lại đã được hòa trộn vào\n"
-"         `%s', nhưng vẫn chưa được hòa trộn vào HEAD."
+"đang xóa nhánh “%s” mà nó lại đã được hòa trộn vào\n"
+"         “%s”, nhưng vẫn chưa được hòa trộn vào HEAD."
 
 #: builtin/branch.c:149
 #, c-format
@@ -2203,269 +2244,269 @@ msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
 "         '%s', even though it is merged to HEAD."
 msgstr ""
-"không xóa nhánh `%s' cái mà chưa được hòa trộng vào\n"
-"         `%s', cho dù là nó đã được hòa trộn vào HEAD."
+"không xóa nhánh “%s” cái mà chưa được hòa trộn vào\n"
+"         “%s”, cho dù là nó đã được hòa trộn vào HEAD."
+
+#: builtin/branch.c:163
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho “%s”"
+
+#: builtin/branch.c:167
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+"Nhánh “%s” không được trộn một cách đầy đủ.\n"
+"Nếu bạn thực sự muốn xóa nó, thì chạy lệnh “git branch -D %s”."
 
-#: builtin/branch.c:181
+#: builtin/branch.c:180
+msgid "Update of config-file failed"
+msgstr "Cập nhật tập tin cấu hình gặp lỗi"
+
+#: builtin/branch.c:208
 msgid "cannot use -a with -d"
 msgstr "không thể dùng tùy chọn -a với -d"
 
-#: builtin/branch.c:187
+#: builtin/branch.c:214
 msgid "Couldn't look up commit object for HEAD"
 msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho HEAD"
 
-#: builtin/branch.c:192
+#: builtin/branch.c:222
 #, c-format
 msgid "Cannot delete the branch '%s' which you are currently on."
-msgstr "Không thể xóa nhánh `%s' cái mà bạn hiện nay đang ở."
+msgstr "Không thể xóa nhánh “%s” cái mà bạn hiện nay đang ở."
 
-#: builtin/branch.c:203
+#: builtin/branch.c:235
 #, c-format
 msgid "remote branch '%s' not found."
-msgstr "không tìm thấy nhánh máy chủ `%s'."
+msgstr "không tìm thấy nhánh máy chủ “%s”."
 
-#: builtin/branch.c:204
+#: builtin/branch.c:236
 #, c-format
 msgid "branch '%s' not found."
-msgstr "không tìm thấy nhánh `%s'."
+msgstr "không tìm thấy nhánh “%s”."
 
-#: builtin/branch.c:211
-#, c-format
-msgid "Couldn't look up commit object for '%s'"
-msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho `%s'"
-
-#: builtin/branch.c:217
-#, c-format
-msgid ""
-"The branch '%s' is not fully merged.\n"
-"If you are sure you want to delete it, run 'git branch -D %s'."
-msgstr ""
-"Nhánh `%s' không được trộn một cách đầy đủ.\n"
-"Nếu bạn thực sự muốn xóa nó, thì chạy lệnh `git branch -D %s'."
-
-#: builtin/branch.c:226
+#: builtin/branch.c:250
 #, c-format
 msgid "Error deleting remote branch '%s'"
-msgstr "Gặp lỗi khi đang xóa nhánh máy chủ `%s'"
+msgstr "Gặp lỗi khi đang xóa nhánh máy chủ “%s”"
 
-#: builtin/branch.c:227
+#: builtin/branch.c:251
 #, c-format
 msgid "Error deleting branch '%s'"
-msgstr "Lỗi khi xoá bỏ nhánh `%s'"
+msgstr "Lỗi khi xoá bỏ nhánh “%s”"
 
-#: builtin/branch.c:234
+#: builtin/branch.c:258
 #, c-format
 msgid "Deleted remote branch %s (was %s).\n"
 msgstr "Nhánh máy chủ \"%s\" đã bị xóa (từng là %s).\n"
 
-#: builtin/branch.c:235
+#: builtin/branch.c:259
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
-msgstr "Nhánh `%s' đã bị xóa (từng là %s)\n"
+msgstr "Nhánh “%s” đã bị xóa (từng là %s)\n"
 
-#: builtin/branch.c:240
-msgid "Update of config-file failed"
-msgstr "Cập nhật tập tin cấu hình gặp lỗi"
-
-#: builtin/branch.c:338
+#: builtin/branch.c:361
 #, c-format
 msgid "branch '%s' does not point at a commit"
-msgstr "nhánh `%s' không chỉ đến một lần chuyển giao (commit) nào cả"
+msgstr "nhánh “%s” không chỉ đến một lần chuyển giao (commit) nào cả"
 
-#: builtin/branch.c:410
+#: builtin/branch.c:433
 #, c-format
 msgid "[%s: behind %d]"
 msgstr "[%s: đằng sau %d]"
 
-#: builtin/branch.c:412
+#: builtin/branch.c:435
 #, c-format
 msgid "[behind %d]"
 msgstr "[đằng sau %d]"
 
-#: builtin/branch.c:416
+#: builtin/branch.c:439
 #, c-format
 msgid "[%s: ahead %d]"
 msgstr "[%s: phía trước %d]"
 
-#: builtin/branch.c:418
+#: builtin/branch.c:441
 #, c-format
 msgid "[ahead %d]"
 msgstr "[phía trước %d]"
 
-#: builtin/branch.c:421
+#: builtin/branch.c:444
 #, c-format
 msgid "[%s: ahead %d, behind %d]"
 msgstr "[%s: trước %d, sau %d]"
 
-#: builtin/branch.c:424
+#: builtin/branch.c:447
 #, c-format
 msgid "[ahead %d, behind %d]"
 msgstr "[trước %d, sau %d]"
 
-#: builtin/branch.c:537
+#: builtin/branch.c:560
 msgid "(no branch)"
 msgstr "(không nhánh)"
 
-#: builtin/branch.c:602
+#: builtin/branch.c:625
 msgid "some refs could not be read"
 msgstr "một số tham chiếu đã không thể đọc được"
 
-#: builtin/branch.c:615
+#: builtin/branch.c:638
 msgid "cannot rename the current branch while not on any."
 msgstr "không thể đổi tên nhánh hiện hành trong khi nó chẳng ở đâu cả."
 
-#: builtin/branch.c:625
+#: builtin/branch.c:648
 #, c-format
 msgid "Invalid branch name: '%s'"
-msgstr "Sai tên nhánh: `%s'"
+msgstr "Sai tên nhánh: “%s”"
 
-#: builtin/branch.c:640
+#: builtin/branch.c:663
 msgid "Branch rename failed"
 msgstr "Đổi tên nhánh gặp lỗi"
 
-#: builtin/branch.c:644
+#: builtin/branch.c:667
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
-msgstr "Đã đổi tên nhánh khuyết danh `%s' đi"
+msgstr "Đã đổi tên nhánh khuyết danh “%s” đi"
 
-#: builtin/branch.c:648
+#: builtin/branch.c:671
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr "Nhánh bị đổi tên thành %s, nhưng HEAD lại không được cập nhật!"
 
-#: builtin/branch.c:655
+#: builtin/branch.c:678
 msgid "Branch is renamed, but update of config-file failed"
 msgstr "Nhánh bị đổi tên, nhưng cập nhật tập tin cấu hình gặp lỗi"
 
-#: builtin/branch.c:670
+#: builtin/branch.c:693
 #, c-format
 msgid "malformed object name %s"
 msgstr "tên đối tượng dị hình %s"
 
-#: builtin/branch.c:694
+#: builtin/branch.c:717
 #, c-format
 msgid "could not write branch description template: %s"
 msgstr "không thể ghi vào mẫu mô tả nhánh: %s"
 
-#: builtin/branch.c:724
+#: builtin/branch.c:747
 msgid "Generic options"
 msgstr "Tùy chọn chung"
 
-#: builtin/branch.c:726
+#: builtin/branch.c:749
 msgid "show hash and subject, give twice for upstream branch"
 msgstr "hiển thị mã băm và chủ đề, đưa ra hai lần cho nhánh thượng nguồn"
 
-#: builtin/branch.c:727
+#: builtin/branch.c:750
 msgid "suppress informational messages"
 msgstr "Thu hồi các thông điệp thông tin"
 
-#: builtin/branch.c:728
+#: builtin/branch.c:751
 msgid "set up tracking mode (see git-pull(1))"
 msgstr "cài đặt chế độ theo vết (xem git-pull(1))"
 
-#: builtin/branch.c:730
+#: builtin/branch.c:753
 msgid "change upstream info"
 msgstr "thay đổi thông tin thượng nguồn (upstream)"
 
-#: builtin/branch.c:734
+#: builtin/branch.c:757
 msgid "use colored output"
 msgstr "sử dụng kết xuất có tô màu"
 
-#: builtin/branch.c:735
+#: builtin/branch.c:758
 msgid "act on remote-tracking branches"
-msgstr "thao tác trên nhánh `remote-tracking'"
+msgstr "thao tác trên nhánh “remote-tracking”"
 
-#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
-#: builtin/branch.c:771 builtin/commit.c:1362 builtin/commit.c:1363
-#: builtin/commit.c:1364 builtin/commit.c:1365 builtin/tag.c:470
+#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788
+#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377
+#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470
 msgid "commit"
 msgstr "commit"
 
-#: builtin/branch.c:739 builtin/branch.c:745
+#: builtin/branch.c:762 builtin/branch.c:768
 msgid "print only branches that contain the commit"
 msgstr "chỉ hiển thị những nhánh mà nó chứa lần chuyển giao"
 
-#: builtin/branch.c:751
+#: builtin/branch.c:774
 msgid "Specific git-branch actions:"
 msgstr "Hành động git-branch:"
 
-#: builtin/branch.c:752
+#: builtin/branch.c:775
 msgid "list both remote-tracking and local branches"
-msgstr "liệt kê cả nhánh `remote-tracking' và nội bộ"
+msgstr "liệt kê cả nhánh “remote-tracking” và nội bộ"
 
-#: builtin/branch.c:754
+#: builtin/branch.c:777
 msgid "delete fully merged branch"
 msgstr "xóa một cách đầy đủ nhánh đã hòa trộn"
 
-#: builtin/branch.c:755
+#: builtin/branch.c:778
 msgid "delete branch (even if not merged)"
 msgstr "xoá nhánh (cho dù là chưa được hòa trộn)"
 
-#: builtin/branch.c:756
+#: builtin/branch.c:779
 msgid "move/rename a branch and its reflog"
 msgstr "di chuyển hay đổi tên một nhánh và reflog của nó"
 
-#: builtin/branch.c:757
+#: builtin/branch.c:780
 msgid "move/rename a branch, even if target exists"
-msgstr "di chuyể hoặc đổi tên một nhánh, thậm  chí cả khi đích đã có sẵn"
+msgstr "di chuyển hoặc đổi tên một nhánh, thậm chí cả khi đích đã có sẵn"
 
-#: builtin/branch.c:758
+#: builtin/branch.c:781
 msgid "list branch names"
 msgstr "liệt kê các tên nhánh"
 
-#: builtin/branch.c:759
+#: builtin/branch.c:782
 msgid "create the branch's reflog"
 msgstr "tạo reflog của nhánh"
 
-#: builtin/branch.c:761
+#: builtin/branch.c:784
 msgid "edit the description for the branch"
 msgstr "sửa mô tả cho nhánh"
 
-#: builtin/branch.c:762
+#: builtin/branch.c:785
 msgid "force creation (when already exists)"
 msgstr "ép buộc tạo (khi đã sẵn tồn tại rồi)"
 
-#: builtin/branch.c:765
+#: builtin/branch.c:788
 msgid "print only not merged branches"
 msgstr "chỉ hiển thị các nhánh chưa được hòa trộn"
 
-#: builtin/branch.c:771
+#: builtin/branch.c:794
 msgid "print only merged branches"
 msgstr "chỉ hiển thị các nhánh được hòa trộn"
 
-#: builtin/branch.c:775
+#: builtin/branch.c:798
 msgid "list branches in columns"
 msgstr "liệt kê các nhánh trong các cột"
 
-#: builtin/branch.c:788
+#: builtin/branch.c:811
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "Gặp lỗi khi giải quyết HEAD như là một tham chiếu (ref) hợp lệ."
 
-#: builtin/branch.c:793 builtin/clone.c:561
+#: builtin/branch.c:816 builtin/clone.c:561
 msgid "HEAD not found below refs/heads!"
 msgstr "không tìm thấy HEAD ở dưới refs/heads!"
 
-#: builtin/branch.c:813
+#: builtin/branch.c:836
 msgid "--column and --verbose are incompatible"
 msgstr "--column và --verbose xung khắc nhau"
 
-#: builtin/branch.c:864
+#: builtin/branch.c:887
 #, c-format
 msgid "branch '%s' does not exist"
-msgstr "nhánh `%s' chưa sẵn có"
+msgstr "nhánh “%s” chưa sẵn có"
 
-#: builtin/branch.c:876
+#: builtin/branch.c:899
 #, c-format
 msgid "Branch '%s' has no upstream information"
-msgstr "Nhánh `%s' không có thông tin thượng nguồn (upstream)"
+msgstr "Nhánh “%s” không có thông tin thượng nguồn (upstream)"
 
-#: builtin/branch.c:891
+#: builtin/branch.c:914
 msgid "-a and -r options to 'git branch' do not make sense with a branch name"
 msgstr ""
-"hai tùy chọn -a và -r áp dụng cho lệnh `git branch' không hợp lý đối với tên "
+"hai tùy chọn -a và -r áp dụng cho lệnh “git branch” không hợp lý đối với tên "
 "nhánh"
 
-#: builtin/branch.c:894
+#: builtin/branch.c:917
 #, c-format
 msgid ""
 "The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -2474,7 +2515,7 @@ msgstr ""
 "Cờ --set-upstream bị phản đối và sẽ bị xóa bỏ. Nên dùng --track hoặc --set-"
 "upstream-to\n"
 
-#: builtin/branch.c:911
+#: builtin/branch.c:934
 #, c-format
 msgid ""
 "\n"
@@ -2482,15 +2523,15 @@ msgid ""
 "\n"
 msgstr ""
 "\n"
-"Nếu bạn muốn `%s' theo dõi `%s', thực hiện lệnh sau:\n"
+"Nếu bạn muốn “%s” theo dõi “%s”, thực hiện lệnh sau:\n"
 "\n"
 
-#: builtin/branch.c:912
+#: builtin/branch.c:935
 #, c-format
 msgid "    git branch -d %s\n"
 msgstr "    git branch -d %s\n"
 
-#: builtin/branch.c:913
+#: builtin/branch.c:936
 #, c-format
 msgid "    git branch --set-upstream-to %s\n"
 msgstr "    git branch --set-upstream-to %s\n"
@@ -2498,7 +2539,7 @@ msgstr "    git branch --set-upstream-to %s\n"
 #: builtin/bundle.c:47
 #, c-format
 msgid "%s is okay\n"
-msgstr "`%s' tốt\n"
+msgstr "“%s” tốt\n"
 
 #: builtin/bundle.c:56
 msgid "Need a repository to create a bundle."
@@ -2630,49 +2671,49 @@ msgstr "git checkout [các-tùy-chọn] [<nhánh>] -- <tập-tin>..."
 #: builtin/checkout.c:116 builtin/checkout.c:149
 #, c-format
 msgid "path '%s' does not have our version"
-msgstr "đường dẫn `%s' không có các phiên bản của chúng ta"
+msgstr "đường dẫn “%s” không có các phiên bản của chúng ta"
 
 #: builtin/checkout.c:118 builtin/checkout.c:151
 #, c-format
 msgid "path '%s' does not have their version"
-msgstr "đường dẫn `%s' không có các phiên bản của chúng"
+msgstr "đường dẫn “%s” không có các phiên bản của chúng"
 
 #: builtin/checkout.c:134
 #, c-format
 msgid "path '%s' does not have all necessary versions"
-msgstr "đường dẫn `%s' không có tất cả các phiên bản cần thiết"
+msgstr "đường dẫn “%s” không có tất cả các phiên bản cần thiết"
 
 #: builtin/checkout.c:178
 #, c-format
 msgid "path '%s' does not have necessary versions"
-msgstr "đường dẫn `%s' không có các phiên bản cần thiết"
+msgstr "đường dẫn “%s” không có các phiên bản cần thiết"
 
 #: builtin/checkout.c:195
 #, c-format
 msgid "path '%s': cannot merge"
-msgstr "đường dẫn `%s': không thể hòa trộn"
+msgstr "đường dẫn “%s”: không thể hòa trộn"
 
 #: builtin/checkout.c:212
 #, c-format
 msgid "Unable to add merge result for '%s'"
-msgstr "Không thể thêm kết quả hòa trộn cho `%s'"
+msgstr "Không thể thêm kết quả hòa trộn cho “%s”"
 
 #: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242
 #: builtin/checkout.c:245
 #, c-format
 msgid "'%s' cannot be used with updating paths"
-msgstr "`%s' không thể được sử dụng với các đường dẫn cập nhật"
+msgstr "“%s” không thể được sử dụng với các đường dẫn cập nhật"
 
 #: builtin/checkout.c:248 builtin/checkout.c:251
 #, c-format
 msgid "'%s' cannot be used with %s"
-msgstr "`%s' không thể được sử dụng với %s"
+msgstr "“%s” không thể được sử dụng với %s"
 
 #: builtin/checkout.c:254
 #, c-format
 msgid "Cannot update paths and switch to branch '%s' at the same time."
 msgstr ""
-"Không thể cập nhật các đường dẫn và chuyển đến nhánh `%s' cùng một lúc."
+"Không thể cập nhật các đường dẫn và chuyển đến nhánh “%s” cùng một lúc."
 
 #: builtin/checkout.c:265 builtin/checkout.c:426
 msgid "corrupt index file"
@@ -2681,12 +2722,7 @@ msgstr "tập tin ghi bảng mục lục bị hỏng"
 #: builtin/checkout.c:295 builtin/checkout.c:302
 #, c-format
 msgid "path '%s' is unmerged"
-msgstr "đường dẫn `%s' không được hòa trộn"
-
-#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586
-#: builtin/merge.c:811
-msgid "unable to write new index file"
-msgstr "không thể ghi tập tin lưu bảng mục lục mới"
+msgstr "đường dẫn “%s” không được hòa trộn"
 
 #: builtin/checkout.c:448
 msgid "you need to resolve your current index first"
@@ -2695,7 +2731,7 @@ msgstr "bạn cần phải giải quyết bảng mục lục hiện tại của
 #: builtin/checkout.c:569
 #, c-format
 msgid "Can not do reflog for '%s'\n"
-msgstr "Không thể thực hiện reflog cho `%s'\n"
+msgstr "Không thể thực hiện reflog cho “%s”\n"
 
 #: builtin/checkout.c:602
 msgid "HEAD is now at"
@@ -2704,27 +2740,27 @@ msgstr "HEAD hiện giờ tại"
 #: builtin/checkout.c:609
 #, c-format
 msgid "Reset branch '%s'\n"
-msgstr "Đặt lại nhánh `%s'\n"
+msgstr "Đặt lại nhánh “%s”\n"
 
 #: builtin/checkout.c:612
 #, c-format
 msgid "Already on '%s'\n"
-msgstr "Đã sẵn sàng trên `%s'\n"
+msgstr "Đã sẵn sàng trên “%s”\n"
 
 #: builtin/checkout.c:616
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
-msgstr "Đã chuyển tới và reset nhánh `%s'\n"
+msgstr "Đã chuyển tới và reset nhánh “%s”\n"
 
-#: builtin/checkout.c:618
+#: builtin/checkout.c:618 builtin/checkout.c:955
 #, c-format
 msgid "Switched to a new branch '%s'\n"
-msgstr "Đã chuyển đến nhánh mới `%s'\n"
+msgstr "Đã chuyển đến nhánh mới “%s”\n"
 
 #: builtin/checkout.c:620
 #, c-format
 msgid "Switched to branch '%s'\n"
-msgstr "Đã chuyển đến nhánh `%s'\n"
+msgstr "Đã chuyển đến nhánh “%s”\n"
 
 #: builtin/checkout.c:676
 #, c-format
@@ -2797,129 +2833,129 @@ msgstr "tham chiếu sai: %s"
 msgid "reference is not a tree: %s"
 msgstr "tham chiếu không phải là một cây (tree):%s"
 
-#: builtin/checkout.c:961
+#: builtin/checkout.c:964
 msgid "paths cannot be used with switching branches"
 msgstr "các đường dẫn không thể dùng cùng với các nhánh chuyển"
 
-#: builtin/checkout.c:964 builtin/checkout.c:968
+#: builtin/checkout.c:967 builtin/checkout.c:971
 #, c-format
 msgid "'%s' cannot be used with switching branches"
-msgstr "`%s' không thể được sử dụng với các nhánh chuyển"
+msgstr "“%s” không thể được sử dụng với các nhánh chuyển"
 
-#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980
-#: builtin/checkout.c:983
+#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983
+#: builtin/checkout.c:986
 #, c-format
 msgid "'%s' cannot be used with '%s'"
-msgstr "`%s' không thể được sử dụng với `%s'"
+msgstr "“%s” không thể được sử dụng với “%s”"
 
-#: builtin/checkout.c:988
+#: builtin/checkout.c:991
 #, c-format
 msgid "Cannot switch branch to a non-commit '%s'"
-msgstr "Không thể chuyển nhánh đến một non-commit `%s'"
+msgstr "Không thể chuyển nhánh đến một non-commit “%s”"
 
-#: builtin/checkout.c:1009 builtin/gc.c:177
+#: builtin/checkout.c:1012 builtin/gc.c:177
 msgid "suppress progress reporting"
 msgstr "chặn các báo cáo tiến trình hoạt động"
 
-#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89
+#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89
 #: builtin/remote.c:169 builtin/remote.c:171
 msgid "branch"
 msgstr "nhánh"
 
-#: builtin/checkout.c:1011
+#: builtin/checkout.c:1014
 msgid "create and checkout a new branch"
 msgstr "tạo và checkout một nhánh mới"
 
-#: builtin/checkout.c:1013
+#: builtin/checkout.c:1016
 msgid "create/reset and checkout a branch"
 msgstr "create/reset và checkout một nhánh"
 
-#: builtin/checkout.c:1014
+#: builtin/checkout.c:1017
 msgid "create reflog for new branch"
 msgstr "tạo reflog cho nhánh mới"
 
-#: builtin/checkout.c:1015
+#: builtin/checkout.c:1018
 msgid "detach the HEAD at named commit"
 msgstr "rời bỏ HEAD tại lần chuyển giao danh nghĩa"
 
-#: builtin/checkout.c:1016
+#: builtin/checkout.c:1019
 msgid "set upstream info for new branch"
 msgstr "đặt thông tin thượng nguồn (upstream) cho nhánh mới"
 
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1021
 msgid "new branch"
 msgstr "nhánh mới"
 
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1021
 msgid "new unparented branch"
 msgstr "nhánh mồ côi mới"
 
-#: builtin/checkout.c:1019
+#: builtin/checkout.c:1022
 msgid "checkout our version for unmerged files"
 msgstr ""
 "lấy ra (checkout) phiên bản của chúng ta cho các tập tin chưa được hòa trộn"
 
-#: builtin/checkout.c:1021
+#: builtin/checkout.c:1024
 msgid "checkout their version for unmerged files"
 msgstr ""
 "lấy ra (checkout) phiên bản của chúng họ cho các tập tin chưa được hòa trộn"
 
-#: builtin/checkout.c:1023
+#: builtin/checkout.c:1026
 msgid "force checkout (throw away local modifications)"
 msgstr "ép buộc lấy ra (checkout) (bỏ đi những thay đổi nội bộ)"
 
-#: builtin/checkout.c:1024
+#: builtin/checkout.c:1027
 msgid "perform a 3-way merge with the new branch"
 msgstr "thực hiện hòa trộn kiểu 3-way với nhánh mới"
 
-#: builtin/checkout.c:1025 builtin/merge.c:215
+#: builtin/checkout.c:1028 builtin/merge.c:215
 msgid "update ignored files (default)"
 msgstr "cập nhật các tập tin bị bỏ qua (mặc định)"
 
-#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241
+#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241
 msgid "style"
 msgstr "kiểu"
 
-#: builtin/checkout.c:1027
+#: builtin/checkout.c:1030
 msgid "conflict style (merge or diff3)"
 msgstr "xung đột kiểu (hòa trộn hay diff3)"
 
-#: builtin/checkout.c:1030
+#: builtin/checkout.c:1033
 msgid "second guess 'git checkout no-such-branch'"
-msgstr "gợi ý thứ hai `git checkout không-nhánh-nào-như-vậy'"
+msgstr "gợi ý thứ hai “git checkout không-nhánh-nào-như-vậy”"
 
-#: builtin/checkout.c:1054
+#: builtin/checkout.c:1057
 msgid "-b, -B and --orphan are mutually exclusive"
 msgstr "Tùy chọn -b|-B và --orphan loại từ lẫn nhau"
 
-#: builtin/checkout.c:1071
+#: builtin/checkout.c:1074
 msgid "--track needs a branch name"
 msgstr "--track cần tên một nhánh"
 
-#: builtin/checkout.c:1078
+#: builtin/checkout.c:1081
 msgid "Missing branch name; try -b"
 msgstr "Thiếu tên nhánh; hãy thử -b"
 
-#: builtin/checkout.c:1113
+#: builtin/checkout.c:1116
 msgid "invalid path specification"
 msgstr "đường dẫn đã cho không hợp lệ"
 
-#: builtin/checkout.c:1120
+#: builtin/checkout.c:1123
 #, c-format
 msgid ""
 "Cannot update paths and switch to branch '%s' at the same time.\n"
 "Did you intend to checkout '%s' which can not be resolved as commit?"
 msgstr ""
-"Không thể cập nhật và chuyển thành nhánh `%s' cùng lúc\n"
-"Bạn đã có ý định checkout `%s' cái mà không thể được phân giải như là lần "
+"Không thể cập nhật và chuyển thành nhánh “%s” cùng lúc\n"
+"Bạn đã có ý định checkout “%s” cái mà không thể được phân giải như là lần "
 "chuyển giao (commit)?"
 
-#: builtin/checkout.c:1125
+#: builtin/checkout.c:1128
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
-msgstr "git checkout: --detach không nhận một đối số đường dẫn `%s'"
+msgstr "git checkout: --detach không nhận một đối số đường dẫn “%s”"
 
-#: builtin/checkout.c:1129
+#: builtin/checkout.c:1132
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
 "checking out of the index."
@@ -2943,8 +2979,8 @@ msgstr "ép buộc"
 msgid "remove whole directories"
 msgstr "gỡ bỏ toàn bộ thư mục"
 
-#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:803
-#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717
+#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182
 msgid "pattern"
 msgstr "mẫu"
 
@@ -3059,7 +3095,7 @@ msgstr "tên"
 
 #: builtin/clone.c:88
 msgid "use <name> instead of 'origin' to track upstream"
-msgstr "dùng <tên> thay vì `origin' để theo dõi thượng nguồn (uptream)"
+msgstr "dùng <tên> thay vì “origin” để theo dõi thượng nguồn (uptream)"
 
 #: builtin/clone.c:90
 msgid "checkout <branch> instead of the remote's HEAD"
@@ -3069,7 +3105,7 @@ msgstr "lấy ra nhánh (checkout <nhánh>) thay vì HEAD của máy chủ"
 msgid "path to git-upload-pack on the remote"
 msgstr "đường dẫn đến git-upload-pack trên máy chủ"
 
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:748
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662
 msgid "depth"
 msgstr "độ sâu"
 
@@ -3100,7 +3136,7 @@ msgstr "đặt cấu hình bên trong một kho chứa mới"
 #: builtin/clone.c:243
 #, c-format
 msgid "reference repository '%s' is not a local directory."
-msgstr "kho tham chiếu `%s' không phải là một thư mục nội bộ."
+msgstr "kho tham chiếu “%s” không phải là một thư mục nội bộ."
 
 #: builtin/clone.c:306
 #, c-format
@@ -3110,7 +3146,7 @@ msgstr "tạo thư mục \"%s\" gặp lỗi"
 #: builtin/clone.c:308 builtin/diff.c:77
 #, c-format
 msgid "failed to stat '%s'"
-msgstr "gặp lỗi stat (lấy trạng thái về) `%s'"
+msgstr "gặp lỗi stat (lấy trạng thái về) “%s”"
 
 #: builtin/clone.c:310
 #, c-format
@@ -3130,7 +3166,7 @@ msgstr "gặp lỗi khi tạo được liên kết mềm %s"
 #: builtin/clone.c:350
 #, c-format
 msgid "failed to copy file to '%s'"
-msgstr "gặp lỗi khi chép tập tin tới `%s'"
+msgstr "gặp lỗi khi chép tập tin tới “%s”"
 
 #: builtin/clone.c:373
 #, c-format
@@ -3162,7 +3198,7 @@ msgstr "tùy chọn --bare và --origin %s xung khắc nhau."
 #: builtin/clone.c:719
 #, c-format
 msgid "repository '%s' does not exist"
-msgstr "kho chứa `%s' chưa tồn tại"
+msgstr "kho chứa “%s” chưa tồn tại"
 
 #: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
@@ -3171,32 +3207,32 @@ msgstr "--depth bị lờ đi khi nhân bản nội bộ; hãy sử dụng file:
 #: builtin/clone.c:734
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
-msgstr "đường dẫn đích `%s' đã có từ trước và không phải là một thư mục rỗng."
+msgstr "đường dẫn đích “%s” đã có từ trước và không phải là một thư mục rỗng."
 
 #: builtin/clone.c:744
 #, c-format
 msgid "working tree '%s' already exists."
-msgstr "cây làm việc `%s' đã sẵn tồn tại rồi."
+msgstr "cây làm việc “%s” đã sẵn tồn tại rồi."
 
 #: builtin/clone.c:757 builtin/clone.c:771
 #, c-format
 msgid "could not create leading directories of '%s'"
-msgstr "không thể tạo các thư mục dẫn đầu của `%s'"
+msgstr "không thể tạo các thư mục dẫn đầu của “%s”"
 
 #: builtin/clone.c:760
 #, c-format
 msgid "could not create work tree dir '%s'."
-msgstr "không thể tạo cây thư mục làm việc dir `%s'."
+msgstr "không thể tạo cây thư mục làm việc dir “%s”."
 
 #: builtin/clone.c:779
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
-msgstr "Đang nhân bản thành kho chứa bare `%s'...\n"
+msgstr "Đang nhân bản thành kho chứa bare “%s”...\n"
 
 #: builtin/clone.c:781
 #, c-format
 msgid "Cloning into '%s'...\n"
-msgstr "Đang nhân bản thành `%s'...\n"
+msgstr "Đang nhân bản thành “%s”...\n"
 
 #: builtin/clone.c:823
 #, c-format
@@ -3308,99 +3344,99 @@ msgstr ""
 "\n"
 "    git commit --allow-empty\n"
 "\n"
-"Nếu không, hãy thử dùng `git reset'\n"
+"Nếu không, hãy thử dùng “git reset”\n"
 
-#: builtin/commit.c:257
+#: builtin/commit.c:258
 msgid "failed to unpack HEAD tree object"
 msgstr "gặp lỗi khi tháo dỡ HEAD đối tượng cây"
 
-#: builtin/commit.c:299
+#: builtin/commit.c:300
 msgid "unable to create temporary index"
 msgstr "không thể tạo bảng mục lục tạm thời"
 
-#: builtin/commit.c:305
+#: builtin/commit.c:306
 msgid "interactive add failed"
 msgstr "việc thêm tương tác gặp lỗi"
 
-#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
+#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410
 msgid "unable to write new_index file"
 msgstr "không thể ghi tập tin lưu bảng mục lục mới (new_index)"
 
-#: builtin/commit.c:390
+#: builtin/commit.c:391
 msgid "cannot do a partial commit during a merge."
 msgstr ""
 "không thể thực hiện việc chuyển giao (commit) cục bộ trong khi đang được hòa "
 "trộn."
 
-#: builtin/commit.c:392
+#: builtin/commit.c:393
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr ""
 "không thể thực hiện việc chuyển giao (commit) bộ phận trong khi đang cherry-"
 "pick."
 
-#: builtin/commit.c:402
+#: builtin/commit.c:403
 msgid "cannot read the index"
 msgstr "không đọc được bảng mục lục"
 
-#: builtin/commit.c:422
+#: builtin/commit.c:423
 msgid "unable to write temporary index file"
 msgstr "không thể ghi tập tin lưu bảng mục lục tạm thời"
 
-#: builtin/commit.c:509 builtin/commit.c:515
+#: builtin/commit.c:511 builtin/commit.c:517
 #, c-format
 msgid "invalid commit: %s"
 msgstr "lần chuyển giao (commit) không hợp lệ: %s"
 
-#: builtin/commit.c:538
+#: builtin/commit.c:540
 msgid "malformed --author parameter"
 msgstr "đối số --author bị dị hình"
 
-#: builtin/commit.c:558
+#: builtin/commit.c:560
 #, c-format
 msgid "Malformed ident string: '%s'"
-msgstr "Chuỗi thụt lề đầu dòng dị hình: `%s'"
+msgstr "Chuỗi thụt lề đầu dòng dị hình: “%s”"
 
-#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
+#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "không thể tìm kiếm commit (lần chuyển giao) %s"
 
-#: builtin/commit.c:608 builtin/shortlog.c:296
+#: builtin/commit.c:610 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(đang đọc thông điệp nhật ký từ đầu vào tiêu chuẩn)\n"
 
-#: builtin/commit.c:610
+#: builtin/commit.c:612
 msgid "could not read log from standard input"
 msgstr "không thể đọc nhật ký từ đầu vào tiêu chuẩn"
 
-#: builtin/commit.c:614
+#: builtin/commit.c:616
 #, c-format
 msgid "could not read log file '%s'"
-msgstr "không đọc được tệp nhật ký `%s'"
+msgstr "không đọc được tệp nhật ký “%s”"
 
-#: builtin/commit.c:620
+#: builtin/commit.c:622
 msgid "commit has empty message"
 msgstr "lần chuyển giao (commit) có ghi chú trống rỗng"
 
-#: builtin/commit.c:636
+#: builtin/commit.c:638
 msgid "could not read MERGE_MSG"
 msgstr "không thể đọc MERGE_MSG"
 
-#: builtin/commit.c:640
+#: builtin/commit.c:642
 msgid "could not read SQUASH_MSG"
 msgstr "không thể đọc SQUASH_MSG"
 
-#: builtin/commit.c:644
+#: builtin/commit.c:646
 #, c-format
 msgid "could not read '%s'"
-msgstr "Không thể đọc `%s'."
+msgstr "Không thể đọc “%s”."
 
-#: builtin/commit.c:705
+#: builtin/commit.c:707
 msgid "could not write commit template"
 msgstr "không thể ghi mẫu commit"
 
-#: builtin/commit.c:716
+#: builtin/commit.c:718
 #, c-format
 msgid ""
 "\n"
@@ -3415,7 +3451,7 @@ msgstr ""
 "\t%s\n"
 "và thử lại.\n"
 
-#: builtin/commit.c:721
+#: builtin/commit.c:723
 #, c-format
 msgid ""
 "\n"
@@ -3430,17 +3466,17 @@ msgstr ""
 "\t%s\n"
 "và thử lại.\n"
 
-#: builtin/commit.c:733
+#: builtin/commit.c:735
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
 msgstr ""
 "Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng "
 "được\n"
-"bắt đầu bằng `#' sẽ được bỏ qua, phần chú thích này nếu rỗng sẽ làm hủy bỏ "
+"bắt đầu bằng “#” sẽ được bỏ qua, phần chú thích này nếu rỗng sẽ làm hủy bỏ "
 "lần chuyển giao (commit).\n"
 
-#: builtin/commit.c:738
+#: builtin/commit.c:740
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -3448,143 +3484,151 @@ msgid ""
 msgstr ""
 "Hãy nhập vào các thông tin để giải thích các thay đổi của bạn.Những dòng "
 "được\n"
-"bắt đầu bằng `#' sẽ được bỏ qua; bạn có thể xóa chúng đi nếu muốn.\n"
+"bắt đầu bằng “#” sẽ được bỏ qua; bạn có thể xóa chúng đi nếu muốn.\n"
 "Phần chú thích này nếu rỗng sẽ làm hủy bỏ lần chuyển giao (commit).\n"
 
-#: builtin/commit.c:751
+#: builtin/commit.c:753
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sTác giả:    %s"
 
-#: builtin/commit.c:758
+#: builtin/commit.c:760
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sNgười chuyển giao (commit): %s"
 
-#: builtin/commit.c:778
+#: builtin/commit.c:780
 msgid "Cannot read index"
 msgstr "không đọc được bảng mục lục"
 
-#: builtin/commit.c:815
+#: builtin/commit.c:817
 msgid "Error building trees"
 msgstr "Gặp lỗi khi xây dựng cây"
 
-#: builtin/commit.c:830 builtin/tag.c:361
+#: builtin/commit.c:832 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "Xin hãy áp dụng thông điệp sử dụng hoặc là tùy chọn -m hoặc là -F.\n"
 
-#: builtin/commit.c:927
+#: builtin/commit.c:929
 #, c-format
 msgid "No existing author found with '%s'"
-msgstr "Không tìm thấy tác giả có sẵn với `%s'"
+msgstr "Không tìm thấy tác giả có sẵn với “%s”"
 
-#: builtin/commit.c:942 builtin/commit.c:1142
+#: builtin/commit.c:944 builtin/commit.c:1148
 #, c-format
 msgid "Invalid untracked files mode '%s'"
-msgstr "Chế độ cho các tập tin không bị theo vết không hợp lệ `%s'"
+msgstr "Chế độ cho các tập tin không bị theo vết không hợp lệ “%s”"
 
-#: builtin/commit.c:982
+#: builtin/commit.c:984
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "Sử dụng cả hai tùy chọn --reset-author và --author không hợp lý"
 
-#: builtin/commit.c:993
+#: builtin/commit.c:995
 msgid "You have nothing to amend."
 msgstr "Không có gì để amend (tu bổ) cả."
 
-#: builtin/commit.c:996
+#: builtin/commit.c:998
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr ""
 "Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện amend (tu bổ)."
 
-#: builtin/commit.c:998
+#: builtin/commit.c:1000
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr ""
 "Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện amend (tu "
 "bổ)."
 
-#: builtin/commit.c:1001
+#: builtin/commit.c:1003
 msgid "Options --squash and --fixup cannot be used together"
 msgstr "Các tùy chọn --squash và --fixup không thể sử dụng cùng với nhau"
 
-#: builtin/commit.c:1011
+#: builtin/commit.c:1013
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "Chỉ một tùy chọn trong số -c/-C/-F/--fixup được sử dụng"
 
-#: builtin/commit.c:1013
+#: builtin/commit.c:1015
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr "Tùy chọn -m không thể được tổ hợp cùng với -c/-C/-F/--fixup."
 
-#: builtin/commit.c:1021
+#: builtin/commit.c:1023
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr ""
 "--reset-author chỉ có thể được sử dụng với tùy chọn -C, -c hay --amend."
 
-#: builtin/commit.c:1038
+#: builtin/commit.c:1040
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 "Chỉ một trong các tùy chọn --include/--only/--all/--interactive/--patch được "
 "sử dụng."
 
-#: builtin/commit.c:1040
+#: builtin/commit.c:1042
 msgid "No paths with --include/--only does not make sense."
 msgstr "Không đường dẫn với các tùy chọn --include/--only không hợp lý."
 
-#: builtin/commit.c:1042
+#: builtin/commit.c:1044
 msgid "Clever... amending the last one with dirty index."
 msgstr "Giỏi...  tu bổ cái cuối với bảng mục lục phi nghĩa."
 
-#: builtin/commit.c:1044
+#: builtin/commit.c:1046
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr ""
 "Những đường dẫn rõ ràng được chỉ ra không có tùy chọn -i cũng không -o; đang "
 "giả định --only những-đường-dẫn..."
 
-#: builtin/commit.c:1054 builtin/tag.c:577
+#: builtin/commit.c:1056 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Chế độ dọn dẹp không hợp lệ %s"
 
-#: builtin/commit.c:1059
+#: builtin/commit.c:1061
 msgid "Paths with -a does not make sense."
 msgstr "Các đường dẫn với tùy chọn -a không hợp lý."
 
-#: builtin/commit.c:1156 builtin/commit.c:1384
+#: builtin/commit.c:1067 builtin/commit.c:1202
+msgid "--long and -z are incompatible"
+msgstr "hai tùy chọn -long và -z không tương thích với nhau"
+
+#: builtin/commit.c:1162 builtin/commit.c:1398
 msgid "show status concisely"
 msgstr "hiển thị trạng thái ở dạng súc tích"
 
-#: builtin/commit.c:1158 builtin/commit.c:1386
+#: builtin/commit.c:1164 builtin/commit.c:1400
 msgid "show branch information"
 msgstr "hiển thị thông tin nhánh"
 
-#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
+#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389
 msgid "machine-readable output"
 msgstr "kết xuất dạng máy-có-thể-đọc"
 
-#: builtin/commit.c:1163 builtin/commit.c:1390
+#: builtin/commit.c:1169 builtin/commit.c:1404
+msgid "show status in long format (default)"
+msgstr "hiển thị trạng thái ở định dạng dài (mặc định)"
+
+#: builtin/commit.c:1172 builtin/commit.c:1407
 msgid "terminate entries with NUL"
 msgstr "chấm dứt các mục bằng NUL"
 
-#: builtin/commit.c:1165 builtin/commit.c:1393 builtin/fast-export.c:636
+#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636
 #: builtin/fast-export.c:639 builtin/tag.c:461
 msgid "mode"
 msgstr "chế độ"
 
-#: builtin/commit.c:1166 builtin/commit.c:1393
+#: builtin/commit.c:1175 builtin/commit.c:1410
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "hiển thị các tập tin chưa được theo dõi  dấu vết, các chế độ tùy chọn:  all, "
 "normal, no. (Mặc định: all)"
 
-#: builtin/commit.c:1169
+#: builtin/commit.c:1178
 msgid "show ignored files"
 msgstr "hiển thị các tập tin ẩn"
 
-#: builtin/commit.c:1170 parse-options.h:151
+#: builtin/commit.c:1179 parse-options.h:151
 msgid "when"
 msgstr "khi"
 
-#: builtin/commit.c:1171
+#: builtin/commit.c:1180
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
@@ -3592,223 +3636,223 @@ msgstr ""
 "bỏ qua các thay đổi trong mô-đun con, tùy chọn khi: all, dirty, untracked. "
 "(Mặc định: all)"
 
-#: builtin/commit.c:1173
+#: builtin/commit.c:1182
 msgid "list untracked files in columns"
 msgstr "hiển thị danh sách các tập-tin chưa được theo dõi trong các cột"
 
-#: builtin/commit.c:1242
+#: builtin/commit.c:1256
 msgid "couldn't look up newly created commit"
 msgstr "không thể tìm thấy lần chuyển giao (commit) mới hơn đã được tạo"
 
-#: builtin/commit.c:1244
+#: builtin/commit.c:1258
 msgid "could not parse newly created commit"
 msgstr ""
 "không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
 
-#: builtin/commit.c:1285
+#: builtin/commit.c:1299
 msgid "detached HEAD"
 msgstr "đã rời khỏi HEAD"
 
-#: builtin/commit.c:1287
+#: builtin/commit.c:1301
 msgid " (root-commit)"
 msgstr " (root-commit)"
 
-#: builtin/commit.c:1354
+#: builtin/commit.c:1368
 msgid "suppress summary after successful commit"
 msgstr "không hiển thị tổng kết sau khi chuyển giao thành công"
 
-#: builtin/commit.c:1355
+#: builtin/commit.c:1369
 msgid "show diff in commit message template"
 msgstr "hiển thị sự khác biệt trong mẫu tin nhắn chuyển giao"
 
-#: builtin/commit.c:1357
+#: builtin/commit.c:1371
 msgid "Commit message options"
 msgstr "Các tùy chọn ghi chú commit"
 
-#: builtin/commit.c:1358 builtin/tag.c:459
+#: builtin/commit.c:1372 builtin/tag.c:459
 msgid "read message from file"
 msgstr "đọc chú thích từ tập tin"
 
-#: builtin/commit.c:1359
+#: builtin/commit.c:1373
 msgid "author"
 msgstr "tác giả"
 
-#: builtin/commit.c:1359
+#: builtin/commit.c:1373
 msgid "override author for commit"
 msgstr "ghi đè tác giả cho commit"
 
-#: builtin/commit.c:1360 builtin/gc.c:178
+#: builtin/commit.c:1374 builtin/gc.c:178
 msgid "date"
 msgstr "ngày tháng"
 
-#: builtin/commit.c:1360
+#: builtin/commit.c:1374
 msgid "override date for commit"
 msgstr "ghi đè ngày tháng cho commit"
 
-#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537
 #: builtin/notes.c:694 builtin/tag.c:457
 msgid "message"
 msgstr "thông điệp"
 
-#: builtin/commit.c:1361
+#: builtin/commit.c:1375
 msgid "commit message"
 msgstr "chú thích của lần commit"
 
-#: builtin/commit.c:1362
+#: builtin/commit.c:1376
 msgid "reuse and edit message from specified commit"
 msgstr ""
 "dùng lại các ghi chú từ lần chuyển giao (commit) đã cho nhưng có cho sửa chữa"
 
-#: builtin/commit.c:1363
+#: builtin/commit.c:1377
 msgid "reuse message from specified commit"
 msgstr "dùng lại các ghi chú từ lần chuyển giao (commit) đã cho"
 
-#: builtin/commit.c:1364
+#: builtin/commit.c:1378
 msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
 "dùng ghi chú có định dạng autosquash để sửa chữa lần chuyển giao đã chỉ ra"
 
-#: builtin/commit.c:1365
+#: builtin/commit.c:1379
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 "dùng lời nhắn có định dạng tự động nén để nén lại các lần chuyển giao đã chỉ "
 "ra"
 
-#: builtin/commit.c:1366
+#: builtin/commit.c:1380
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr ""
 "lần chuyển giao nhận tôi là tác giả (được dùng với tùy chọn -C/-c/--amend)"
 
-#: builtin/commit.c:1367 builtin/log.c:1068 builtin/revert.c:109
+#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109
 msgid "add Signed-off-by:"
 msgstr "thêm dòng Signed-off-by:"
 
-#: builtin/commit.c:1368
+#: builtin/commit.c:1382
 msgid "use specified template file"
 msgstr "sử dụng tập tin mẫu đã cho"
 
-#: builtin/commit.c:1369
+#: builtin/commit.c:1383
 msgid "force edit of commit"
 msgstr "ép buộc sửa lần commit"
 
-#: builtin/commit.c:1370
+#: builtin/commit.c:1384
 msgid "default"
 msgstr "mặc định"
 
-#: builtin/commit.c:1370 builtin/tag.c:462
+#: builtin/commit.c:1384 builtin/tag.c:462
 msgid "how to strip spaces and #comments from message"
 msgstr "làm thế nào để cắt bỏ khoảng trắng và #ghichú từ mẩu tin nhắn"
 
-#: builtin/commit.c:1371
+#: builtin/commit.c:1385
 msgid "include status in commit message template"
 msgstr "bao gồm các trạng thái ghi mẫu ghi chú chuyển giao (commit)"
 
-#: builtin/commit.c:1372 builtin/merge.c:213 builtin/tag.c:463
+#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463
 msgid "key id"
 msgstr "id khóa"
 
-#: builtin/commit.c:1373 builtin/merge.c:214
+#: builtin/commit.c:1387 builtin/merge.c:214
 msgid "GPG sign commit"
 msgstr "ký lần commit dùng GPG"
 
 #. end commit message options
-#: builtin/commit.c:1376
+#: builtin/commit.c:1390
 msgid "Commit contents options"
 msgstr "Các tùy nội dung ghi chú commit"
 
-#: builtin/commit.c:1377
+#: builtin/commit.c:1391
 msgid "commit all changed files"
 msgstr "chuyển giao tất cả các tập tin có thay đổi"
 
-#: builtin/commit.c:1378
+#: builtin/commit.c:1392
 msgid "add specified files to index for commit"
 msgstr "thêm các tập tin đã chỉ ra vào bảng mục lục để chuyển giao (commit)"
 
-#: builtin/commit.c:1379
+#: builtin/commit.c:1393
 msgid "interactively add files"
 msgstr "thêm các tập-tin bằng tương tác"
 
-#: builtin/commit.c:1380
+#: builtin/commit.c:1394
 msgid "interactively add changes"
 msgstr "thêm các thay đổi bằng tương tác"
 
-#: builtin/commit.c:1381
+#: builtin/commit.c:1395
 msgid "commit only specified files"
 msgstr "chỉ chuyển giao các tập tin đã chỉ ra"
 
-#: builtin/commit.c:1382
+#: builtin/commit.c:1396
 msgid "bypass pre-commit hook"
 msgstr "vòng qua móc (hook) pre-commit"
 
-#: builtin/commit.c:1383
+#: builtin/commit.c:1397
 msgid "show what would be committed"
 msgstr "hiển thị xem cái gì có thể được chuyển giao"
 
-#: builtin/commit.c:1391
+#: builtin/commit.c:1408
 msgid "amend previous commit"
 msgstr "tu bổ (amend) lần commit trước"
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1409
 msgid "bypass post-rewrite hook"
 msgstr "vòng qua móc (hook) post-rewrite"
 
-#: builtin/commit.c:1397
+#: builtin/commit.c:1414
 msgid "ok to record an empty change"
 msgstr "ok để ghi lại một thay đổi trống rỗng"
 
-#: builtin/commit.c:1400
+#: builtin/commit.c:1417
 msgid "ok to record a change with an empty message"
 msgstr "ok để ghi các thay đổi với lời nhắn trống rỗng"
 
-#: builtin/commit.c:1432
+#: builtin/commit.c:1449
 msgid "could not parse HEAD commit"
 msgstr "không thể phân tích commit (lần chuyển giao) HEAD"
 
-#: builtin/commit.c:1470 builtin/merge.c:508
+#: builtin/commit.c:1487 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
-msgstr "không thể mở `%s' để đọc"
+msgstr "không thể mở “%s” để đọc"
 
-#: builtin/commit.c:1477
+#: builtin/commit.c:1494
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Tập tin MERGE_HEAD sai hỏng (%s)"
 
-#: builtin/commit.c:1484
+#: builtin/commit.c:1501
 msgid "could not read MERGE_MODE"
 msgstr "không thể đọc MERGE_MODE"
 
-#: builtin/commit.c:1503
+#: builtin/commit.c:1520
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "không thể đọc thông điệp (message) commit (lần chuyển giao): %s"
 
-#: builtin/commit.c:1517
+#: builtin/commit.c:1534
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr ""
 "Đang bỏ qua việc chuyển giao (commit); bạn đã không biên soạn thông điệp "
 "(message).\n"
 
-#: builtin/commit.c:1522
+#: builtin/commit.c:1539
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr ""
 "Đang bỏ qua lần chuyển giao (commit) bởi vì thông điệp của nó trống rỗng.\n"
 
-#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
+#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857
 msgid "failed to write commit object"
 msgstr "gặp lỗi khi ghi đối tượng chuyển giao (commit)"
 
-#: builtin/commit.c:1558
+#: builtin/commit.c:1575
 msgid "cannot lock HEAD ref"
 msgstr "không thể khóa HEAD ref (tham chiếu)"
 
-#: builtin/commit.c:1562
+#: builtin/commit.c:1579
 msgid "cannot update HEAD ref"
 msgstr "không thể cập nhật ref (tham chiếu) HEAD"
 
-#: builtin/commit.c:1573
+#: builtin/commit.c:1590
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -3823,115 +3867,115 @@ msgstr ""
 msgid "git config [options]"
 msgstr "git config [các-tùy-chọn]"
 
-#: builtin/config.c:52
+#: builtin/config.c:51
 msgid "Config file location"
 msgstr "Vị trí tập tin cấu hình"
 
-#: builtin/config.c:53
+#: builtin/config.c:52
 msgid "use global config file"
 msgstr "đặt tập tin cấu hình cần toàn cục"
 
-#: builtin/config.c:54
+#: builtin/config.c:53
 msgid "use system config file"
 msgstr "sử dụng tập tin cấu hình hệ thống"
 
-#: builtin/config.c:55
+#: builtin/config.c:54
 msgid "use repository config file"
 msgstr "dùng tập tin cấu hình của kho"
 
-#: builtin/config.c:56
+#: builtin/config.c:55
 msgid "use given config file"
 msgstr "sử dụng tập tin cấu hình đã cho"
 
-#: builtin/config.c:57
+#: builtin/config.c:56
 msgid "Action"
 msgstr "Hành động"
 
-#: builtin/config.c:58
+#: builtin/config.c:57
 msgid "get value: name [value-regex]"
 msgstr "lấy giá-trị: tên [value-regex]"
 
-#: builtin/config.c:59
+#: builtin/config.c:58
 msgid "get all values: key [value-regex]"
 msgstr "lấy tất cả giá-trị: khóa [value-regex]"
 
-#: builtin/config.c:60
+#: builtin/config.c:59
 msgid "get values for regexp: name-regex [value-regex]"
 msgstr "lấy giá trị cho regexp: name-regex [value-regex]"
 
-#: builtin/config.c:61
+#: builtin/config.c:60
 msgid "replace all matching variables: name value [value_regex]"
 msgstr "thay thế tất cả các biến khớp mẫu: tên giá-trị [value_regex]"
 
-#: builtin/config.c:62
+#: builtin/config.c:61
 msgid "add a new variable: name value"
 msgstr "thêm biến mới: tên giá-trị"
 
-#: builtin/config.c:63
+#: builtin/config.c:62
 msgid "remove a variable: name [value-regex]"
 msgstr "gỡ bỏ biến: tên [value-regex]"
 
-#: builtin/config.c:64
+#: builtin/config.c:63
 msgid "remove all matches: name [value-regex]"
 msgstr "gỡ bỏ mọi cái khớp: tên [value-regex]"
 
-#: builtin/config.c:65
+#: builtin/config.c:64
 msgid "rename section: old-name new-name"
 msgstr "đổi tên chương: tên-cũ tên-mới"
 
-#: builtin/config.c:66
+#: builtin/config.c:65
 msgid "remove a section: name"
 msgstr "gỡ bỏ chương: tên"
 
-#: builtin/config.c:67
+#: builtin/config.c:66
 msgid "list all"
 msgstr "liệt kê tất"
 
-#: builtin/config.c:68
+#: builtin/config.c:67
 msgid "open an editor"
 msgstr "mở một trình biên soạn"
 
-#: builtin/config.c:69 builtin/config.c:70
+#: builtin/config.c:68 builtin/config.c:69
 msgid "slot"
 msgstr "khe"
 
-#: builtin/config.c:69
+#: builtin/config.c:68
 msgid "find the color configured: [default]"
 msgstr "tìm cấu hình màu sắc: [mặc định]"
 
-#: builtin/config.c:70
+#: builtin/config.c:69
 msgid "find the color setting: [stdout-is-tty]"
 msgstr "tìm các cài đặt về màu sắc: [stdout-là-tty]"
 
-#: builtin/config.c:71
+#: builtin/config.c:70
 msgid "Type"
 msgstr "Kiểu"
 
-#: builtin/config.c:72
+#: builtin/config.c:71
 msgid "value is \"true\" or \"false\""
 msgstr "giá trị là \"true\" hoặc \"false\""
 
-#: builtin/config.c:73
+#: builtin/config.c:72
 msgid "value is decimal number"
 msgstr "giá trị ở dạng số thập phân"
 
-#: builtin/config.c:74
+#: builtin/config.c:73
 msgid "value is --bool or --int"
 msgstr "giá trị là --bool hoặc --int"
 
-#: builtin/config.c:75
+#: builtin/config.c:74
 msgid "value is a path (file or directory name)"
 msgstr "giá trị là đường dẫn (tên tập tin hay thư mục)"
 
-#: builtin/config.c:76
+#: builtin/config.c:75
 msgid "Other"
 msgstr "Khác"
 
-#: builtin/config.c:77
+#: builtin/config.c:76
 msgid "terminate values with NUL byte"
 msgstr "chấm dứt giá trị với byte NUL"
 
-#: builtin/config.c:78
+#: builtin/config.c:77
 msgid "respect include directives on lookup"
 msgstr "tôn trọng kể cà các hướng trong tìm kiếm"
 
@@ -3960,7 +4004,7 @@ msgstr "thẻ được chú giải %s không có tên nhúng"
 #: builtin/describe.c:240
 #, c-format
 msgid "tag '%s' is really '%s' here"
-msgstr "thẻ `%s' đã thực sự ở đây `%s' rồi"
+msgstr "thẻ “%s” đã thực sự ở đây “%s” rồi"
 
 #: builtin/describe.c:267
 #, c-format
@@ -3970,12 +4014,12 @@ msgstr "Không phải tên đối tượng %s hợp lệ"
 #: builtin/describe.c:270
 #, c-format
 msgid "%s is not a valid '%s' object"
-msgstr "%s không phải là một đối tượng `%s' hợp lệ"
+msgstr "%s không phải là một đối tượng “%s” hợp lệ"
 
 #: builtin/describe.c:287
 #, c-format
 msgid "no tag exactly matches '%s'"
-msgstr "không có thẻ nào khớp chính xác với `%s'"
+msgstr "không có thẻ nào khớp chính xác với “%s”"
 
 #: builtin/describe.c:289
 #, c-format
@@ -3993,7 +4037,7 @@ msgid ""
 "No annotated tags can describe '%s'.\n"
 "However, there were unannotated tags: try --tags."
 msgstr ""
-"Không có thẻ được chú giải nào được mô tả là `%s'.\n"
+"Không có thẻ được chú giải nào được mô tả là “%s”.\n"
 "Tuy nhiên, ở đây có những thẻ không được chú giải: hãy thử --tags."
 
 #: builtin/describe.c:357
@@ -4002,7 +4046,7 @@ msgid ""
 "No tags can describe '%s'.\n"
 "Try --always, or create some tags."
 msgstr ""
-"Không có thẻ (tag) có thể mô tả `%s'.\n"
+"Không có thẻ (tag) có thể mô tả “%s”.\n"
 "Hãy thử --always, hoặt tạo một số thẻ."
 
 #: builtin/describe.c:378
@@ -4078,36 +4122,36 @@ msgstr "--dirty là xung khắc với các tùy chọn dành cho chuyển giao (
 #: builtin/diff.c:79
 #, c-format
 msgid "'%s': not a regular file or symlink"
-msgstr "`%s': không phải tập tin bình thường hay liên kết tượng trưng"
+msgstr "“%s”: không phải tập tin bình thường hay liên kết tượng trưng"
 
-#: builtin/diff.c:224
+#: builtin/diff.c:228
 #, c-format
 msgid "invalid option: %s"
 msgstr "tùy chọn sai: %s"
 
-#: builtin/diff.c:301
+#: builtin/diff.c:305
 msgid "Not a git repository"
 msgstr "Không phải là kho git"
 
-#: builtin/diff.c:344
+#: builtin/diff.c:348
 #, c-format
 msgid "invalid object '%s' given."
-msgstr "đối tượng đã cho `%s' không hợp lệ."
+msgstr "đối tượng đã cho “%s” không hợp lệ."
 
-#: builtin/diff.c:349
+#: builtin/diff.c:353
 #, c-format
 msgid "more than %d trees given: '%s'"
-msgstr "đã chỉ ra nhiều hơn %d cây (tree): `%s'"
+msgstr "đã chỉ ra nhiều hơn %d cây (tree): “%s”"
 
-#: builtin/diff.c:359
+#: builtin/diff.c:363
 #, c-format
 msgid "more than two blobs given: '%s'"
-msgstr "đã cho nhiều hơn hai đối tượng blob: `%s'"
+msgstr "đã cho nhiều hơn hai đối tượng blob: “%s”"
 
-#: builtin/diff.c:367
+#: builtin/diff.c:371
 #, c-format
 msgid "unhandled object '%s' given."
-msgstr "đã cho đối tượng không thể nắm giữ `%s'."
+msgstr "đã cho đối tượng không thể nắm giữ “%s”."
 
 #: builtin/fast-export.c:22
 msgid "git fast-export [rev-list-opts]"
@@ -4196,7 +4240,7 @@ msgstr "không lấy (fetch) tất cả các thẻ (--no-tags)"
 #: builtin/fetch.c:73
 msgid "prune remote-tracking branches no longer on remote"
 msgstr ""
-"cắt cụt (prune) các nhánh `remote-tracking' không còn tồn tại trên máy chủ "
+"cắt cụt (prune) các nhánh “remote-tracking” không còn tồn tại trên máy chủ "
 "nữa"
 
 #: builtin/fetch.c:74
@@ -4219,7 +4263,7 @@ msgstr "cho phép cập nhật ref (tham chiếu) HEAD"
 msgid "deepen history of shallow clone"
 msgstr "làm sâu hơn lịch sử của bản sao"
 
-#: builtin/fetch.c:85 builtin/log.c:1083
+#: builtin/fetch.c:85 builtin/log.c:1088
 msgid "dir"
 msgstr "tmục"
 
@@ -4307,7 +4351,7 @@ msgid ""
 " 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
 "một số tham chiếu (refs) nội bộ không thể được cập nhật; hãy thử chạy\n"
-" `git remote prune %s' để bỏ đi những nhánh cũ, hay bị xung đột"
+" “git remote prune %s” để bỏ đi những nhánh cũ, hay bị xung đột"
 
 #: builtin/fetch.c:549
 #, c-format
@@ -4393,15 +4437,15 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
 msgstr ""
 "git fmt-merge-msg [-m <thông điệp>] [--log[=<n>]|--no-log] [--file <tập-tin>]"
 
-#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:787
-#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701
+#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175
 #: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
 msgid "n"
 msgstr "n"
 
 #: builtin/fmt-merge-msg.c:654
 msgid "populate log with at most <n> entries from shortlog"
-msgstr "gắn nhật ký với ít nhất <n> mục từ lệnh `shortlog'"
+msgstr "gắn nhật ký với ít nhất <n> mục từ lệnh “shortlog”"
 
 #: builtin/fmt-merge-msg.c:657
 msgid "alias for --log (deprecated)"
@@ -4481,7 +4525,7 @@ msgstr "báo cáo node gốc"
 
 #: builtin/fsck.c:618
 msgid "make index objects head nodes"
-msgstr "tạo ` index objects head nodes'"
+msgstr "tạo “ index objects head nodes”"
 
 #: builtin/fsck.c:619
 msgid "make reflogs head nodes (default)"
@@ -4510,7 +4554,7 @@ msgstr "git gc [các-tùy-chọn]"
 #: builtin/gc.c:63
 #, c-format
 msgid "Invalid %s: '%s'"
-msgstr "%s không hợp lệ: `%s'"
+msgstr "%s không hợp lệ: “%s”"
 
 #: builtin/gc.c:90
 #, c-format
@@ -4543,7 +4587,7 @@ msgstr ""
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
-"Có quá nhiều đối tượng tự do không được dùng đến; hãy chạy lệnh `git prune' "
+"Có quá nhiều đối tượng tự do không được dùng đến; hãy chạy lệnh “git prune” "
 "để xóa bỏ chúng đi."
 
 #: builtin/grep.c:22
@@ -4555,228 +4599,228 @@ msgstr "git grep [các-tùy-chọn] [-e] <mẫu> [<rev>...] [[--] <đường-d
 msgid "grep: failed to create thread: %s"
 msgstr "grep: gặp lỗi tạo tuyến (thread): %s"
 
-#: builtin/grep.c:455
+#: builtin/grep.c:365
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Gặp lỗi với lệnh chdir: %s"
 
-#: builtin/grep.c:531 builtin/grep.c:565
+#: builtin/grep.c:443 builtin/grep.c:478
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "không thể đọc cây (%s)"
 
-#: builtin/grep.c:579
+#: builtin/grep.c:493
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "không thể thực hiện lệnh grep (lọc tìm) từ đối tượng thuộc kiểu %s"
 
-#: builtin/grep.c:637
+#: builtin/grep.c:551
 #, c-format
 msgid "switch `%c' expects a numerical value"
-msgstr "chuyển đến `%c' mong chờ một giá trị bằng số"
+msgstr "chuyển đến `%c' cần một giá trị bằng số"
 
-#: builtin/grep.c:654
+#: builtin/grep.c:568
 #, c-format
 msgid "cannot open '%s'"
-msgstr "không mở được `%s'"
+msgstr "không mở được “%s”"
 
-#: builtin/grep.c:729
+#: builtin/grep.c:643
 msgid "search in index instead of in the work tree"
 msgstr "tìm trong bảng mục lục thay vì trong cây làm việc"
 
-#: builtin/grep.c:731
+#: builtin/grep.c:645
 msgid "find in contents not managed by git"
 msgstr "tìm trong nội dung không được quản lý bởi git"
 
-#: builtin/grep.c:733
+#: builtin/grep.c:647
 msgid "search in both tracked and untracked files"
 msgstr "tìm kiếm các tập tin được và chưa được theo dõi dấu vết"
 
-#: builtin/grep.c:735
+#: builtin/grep.c:649
 msgid "search also in ignored files"
 msgstr "tìm cả trong các tập tin đã bị lờ đi"
 
-#: builtin/grep.c:738
+#: builtin/grep.c:652
 msgid "show non-matching lines"
 msgstr "hiển thị  những dòng không khớp với mẫu"
 
-#: builtin/grep.c:740
+#: builtin/grep.c:654
 msgid "case insensitive matching"
 msgstr "phân biệt chữ hoa/thường"
 
-#: builtin/grep.c:742
+#: builtin/grep.c:656
 msgid "match patterns only at word boundaries"
 msgstr "chỉ khớp mẫu tại đường ranh giới từ"
 
-#: builtin/grep.c:744
+#: builtin/grep.c:658
 msgid "process binary files as text"
 msgstr "xử lý tập tin nhị phân như là dạng văn bản thường"
 
-#: builtin/grep.c:746
+#: builtin/grep.c:660
 msgid "don't match patterns in binary files"
 msgstr "không khớp mẫu trong các tập tin nhị phân"
 
-#: builtin/grep.c:749
+#: builtin/grep.c:663
 msgid "descend at most <depth> levels"
 msgstr "giảm xuống ít nhất mức <sâu>"
 
-#: builtin/grep.c:753
+#: builtin/grep.c:667
 msgid "use extended POSIX regular expressions"
 msgstr "dùng biểu thức chính qui POSIX có mở rộng"
 
-#: builtin/grep.c:756
+#: builtin/grep.c:670
 msgid "use basic POSIX regular expressions (default)"
 msgstr "sử dụng biểu thức chính quy kiểu POSIX (mặc định)"
 
-#: builtin/grep.c:759
+#: builtin/grep.c:673
 msgid "interpret patterns as fixed strings"
 msgstr "diễn dịch các mẫu như là chuỗi cố định"
 
-#: builtin/grep.c:762
+#: builtin/grep.c:676
 msgid "use Perl-compatible regular expressions"
 msgstr "sử dụng biểu thức chính quy tương thích Perl"
 
-#: builtin/grep.c:765
+#: builtin/grep.c:679
 msgid "show line numbers"
 msgstr "hiển thị số của dòng"
 
-#: builtin/grep.c:766
+#: builtin/grep.c:680
 msgid "don't show filenames"
 msgstr "không hiển thị tên tập tin"
 
-#: builtin/grep.c:767
+#: builtin/grep.c:681
 msgid "show filenames"
 msgstr "hiển thị các tên tập tin"
 
-#: builtin/grep.c:769
+#: builtin/grep.c:683
 msgid "show filenames relative to top directory"
 msgstr "hiển thị tên tập tin tương đối với thư mục đỉnh (top)"
 
-#: builtin/grep.c:771
+#: builtin/grep.c:685
 msgid "show only filenames instead of matching lines"
 msgstr "chỉ hiển thị tên tập tin thay vì những dòng khớp với mẫu"
 
-#: builtin/grep.c:773
+#: builtin/grep.c:687
 msgid "synonym for --files-with-matches"
 msgstr "đồng nghĩa với --files-with-matches"
 
-#: builtin/grep.c:776
+#: builtin/grep.c:690
 msgid "show only the names of files without match"
 msgstr "chỉ hiển thị tên cho những tập tin không khớp với mẫu"
 
-#: builtin/grep.c:778
+#: builtin/grep.c:692
 msgid "print NUL after filenames"
 msgstr "thêm NUL vào sau tên tập tin"
 
-#: builtin/grep.c:780
+#: builtin/grep.c:694
 msgid "show the number of matches instead of matching lines"
 msgstr "hiển thị số lượng khớp thay vì những dòng khớp với mẫu"
 
-#: builtin/grep.c:781
+#: builtin/grep.c:695
 msgid "highlight matches"
 msgstr "tô sáng cái khớp"
 
-#: builtin/grep.c:783
+#: builtin/grep.c:697
 msgid "print empty line between matches from different files"
 msgstr "hiển thị dòng trống giữa các lần khớp từ các tập tin khác biệt"
 
-#: builtin/grep.c:785
+#: builtin/grep.c:699
 msgid "show filename only once above matches from same file"
 msgstr ""
 "hiển thị tên tập tin một lần phía trên các lần khớp từ cùng một tập tin"
 
-#: builtin/grep.c:788
+#: builtin/grep.c:702
 msgid "show <n> context lines before and after matches"
 msgstr "hiển thị <n> dòng nội dung phía trước và sau các lần khớp"
 
-#: builtin/grep.c:791
+#: builtin/grep.c:705
 msgid "show <n> context lines before matches"
 msgstr "hiển thị <n> dòng nội dung trước khớp"
 
-#: builtin/grep.c:793
+#: builtin/grep.c:707
 msgid "show <n> context lines after matches"
 msgstr "hiển thị <n> dòng nội dung sau khớp"
 
-#: builtin/grep.c:794
+#: builtin/grep.c:708
 msgid "shortcut for -C NUM"
 msgstr "Dạng tắt cho -C SỐ"
 
-#: builtin/grep.c:797
+#: builtin/grep.c:711
 msgid "show a line with the function name before matches"
 msgstr "hiển thị dòng vói tên hàm trước các lần khớp"
 
-#: builtin/grep.c:799
+#: builtin/grep.c:713
 msgid "show the surrounding function"
 msgstr "hiển thị hàm bao quanh"
 
-#: builtin/grep.c:802
+#: builtin/grep.c:716
 msgid "read patterns from file"
 msgstr "đọc mẫu từ tập-tin"
 
-#: builtin/grep.c:804
+#: builtin/grep.c:718
 msgid "match <pattern>"
 msgstr "match <mẫu>"
 
-#: builtin/grep.c:806
+#: builtin/grep.c:720
 msgid "combine patterns specified with -e"
 msgstr "tổ hợp mẫu được chỉ ra với tùy chọn -e"
 
-#: builtin/grep.c:818
+#: builtin/grep.c:732
 msgid "indicate hit with exit status without output"
 msgstr "đưa ra gợi ý với trạng thái thoát mà không có kết xuất"
 
-#: builtin/grep.c:820
+#: builtin/grep.c:734
 msgid "show only matches from files that match all patterns"
 msgstr "chỉ hiển thị những cái khớp từ tập tin mà nó khớp toàn bộ các mẫu"
 
-#: builtin/grep.c:822
+#: builtin/grep.c:736
 msgid "show parse tree for grep expression"
-msgstr "hiển thị cây phân tích cú pháp cho biểu thức `grep' (tìm kiếm)"
+msgstr "hiển thị cây phân tích cú pháp cho biểu thức “grep” (tìm kiếm)"
 
-#: builtin/grep.c:826
+#: builtin/grep.c:740
 msgid "pager"
 msgstr "trang giấy"
 
-#: builtin/grep.c:826
+#: builtin/grep.c:740
 msgid "show matching files in the pager"
 msgstr "hiển thị các tập tin khớp trong trang giấy"
 
-#: builtin/grep.c:829
+#: builtin/grep.c:743
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "cho phép gọi grep(1) (bị bỏ qua bởi lần dịch này)"
 
-#: builtin/grep.c:830 builtin/show-ref.c:201
+#: builtin/grep.c:744 builtin/show-ref.c:184
 msgid "show usage"
 msgstr "hiển thị cách dùng"
 
-#: builtin/grep.c:921
+#: builtin/grep.c:811
 msgid "no pattern given."
 msgstr "chưa chỉ ra mẫu."
 
-#: builtin/grep.c:935
+#: builtin/grep.c:825
 #, c-format
 msgid "bad object %s"
 msgstr "đối tượng sai %s"
 
-#: builtin/grep.c:976
+#: builtin/grep.c:866
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager chỉ làm việc trên cây-làm-việc"
 
-#: builtin/grep.c:999
+#: builtin/grep.c:889
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached hay --untracked không được sử dụng với --no-index."
 
-#: builtin/grep.c:1004
+#: builtin/grep.c:894
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr ""
 "--no-index hay --untracked không được sử dụng cùng với các tùy chọn liên "
 "quan đến revs."
 
-#: builtin/grep.c:1007
+#: builtin/grep.c:897
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr "--[no-]exclude-standard không thể sử dụng cho nội dung lưu dấu vết."
 
-#: builtin/grep.c:1015
+#: builtin/grep.c:905
 msgid "both --cached and trees are given."
 msgstr "cả hai --cached và các cây phải được chỉ ra."
 
@@ -4839,7 +4883,7 @@ msgstr "git help [--all] [--man|--web|--info] [lệnh]"
 #: builtin/help.c:65
 #, c-format
 msgid "unrecognized help format '%s'"
-msgstr "không nhận ra định dạng trợ giúp `%s'"
+msgstr "không nhận ra định dạng trợ giúp “%s”"
 
 #: builtin/help.c:93
 msgid "Failed to start emacsclient."
@@ -4852,12 +4896,12 @@ msgstr "Gặp lỗi khi phân tích phiên bản emacsclient."
 #: builtin/help.c:114
 #, c-format
 msgid "emacsclient version '%d' too old (< 22)."
-msgstr "phiên bản của emacsclient `%d' quá cũ (< 22)."
+msgstr "phiên bản của emacsclient “%d” quá cũ (< 22)."
 
 #: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177
 #, c-format
 msgid "failed to exec '%s': %s"
-msgstr "gặp lỗi khi thực thi `%s': %s"
+msgstr "gặp lỗi khi thực thi “%s”: %s"
 
 #: builtin/help.c:217
 #, c-format
@@ -4865,8 +4909,8 @@ msgid ""
 "'%s': path for unsupported man viewer.\n"
 "Please consider using 'man.<tool>.cmd' instead."
 msgstr ""
-"`%s': đường dẫn không hỗ trợ bộ trình chiếu man.\n"
-"Hãy cân nhắc đến việc sử dụng 'man.<tool>.cmd' để thay thế."
+"“%s”: đường dẫn không hỗ trợ bộ trình chiếu man.\n"
+"Hãy cân nhắc đến việc sử dụng “man.<tool>.cmd” để thay thế."
 
 #: builtin/help.c:229
 #, c-format
@@ -4874,8 +4918,8 @@ msgid ""
 "'%s': cmd for supported man viewer.\n"
 "Please consider using 'man.<tool>.path' instead."
 msgstr ""
-"`%s': cmd (lệnh) hỗ trợ bộ trình chiếu man.\n"
-"Hãy cân nhắc đến việc sử dụng 'man.<tool>.path' để thay thế."
+"“%s”: cmd (lệnh) hỗ trợ bộ trình chiếu man.\n"
+"Hãy cân nhắc đến việc sử dụng “man.<tool>.path” để thay thế."
 
 #: builtin/help.c:299
 msgid "The most commonly used git commands are:"
@@ -4884,7 +4928,7 @@ msgstr "Những lệnh git hay được sử dụng nhất là:"
 #: builtin/help.c:367
 #, c-format
 msgid "'%s': unknown man viewer."
-msgstr "`%s': không rõ chương trình xem man."
+msgstr "“%s”: không rõ chương trình xem man."
 
 #: builtin/help.c:384
 msgid "no man viewer handled the request"
@@ -4939,12 +4983,12 @@ msgstr "pack quá lớn so với định nghĩa hiện tại của kiểu off_t"
 #: builtin/index-pack.c:273
 #, c-format
 msgid "unable to create '%s'"
-msgstr "không thể tạo `%s'"
+msgstr "không thể tạo “%s”"
 
 #: builtin/index-pack.c:278
 #, c-format
 msgid "cannot open packfile '%s'"
-msgstr "không thể mở packfile `%s'"
+msgstr "không thể mở packfile “%s”"
 
 #: builtin/index-pack.c:292
 msgid "pack signature mismatch"
@@ -5104,12 +5148,12 @@ msgstr "gặp lỗi trong khi đóng tập tin pack"
 #: builtin/index-pack.c:1266
 #, c-format
 msgid "cannot write keep file '%s'"
-msgstr "không thể ghi tập tin giữ lại `%s'"
+msgstr "không thể ghi tập tin giữ lại “%s”"
 
 #: builtin/index-pack.c:1274
 #, c-format
 msgid "cannot close written keep file '%s'"
-msgstr "không thể đóng tập tin giữ lại đã được ghi `%s'"
+msgstr "không thể đóng tập tin giữ lại đã được ghi “%s”"
 
 #: builtin/index-pack.c:1287
 msgid "cannot store pack file"
@@ -5137,12 +5181,12 @@ msgstr "không hỗ trợ đa tuyến, bỏ qua %s"
 #: builtin/index-pack.c:1399
 #, c-format
 msgid "Cannot open existing pack file '%s'"
-msgstr "Không thể mở tập tin pack đã sẵn có `%s'"
+msgstr "Không thể mở tập tin pack đã sẵn có “%s”"
 
 #: builtin/index-pack.c:1401
 #, c-format
 msgid "Cannot open existing pack idx file for '%s'"
-msgstr "Không thể mở tập tin 'pack idx' cho `%s'"
+msgstr "Không thể mở tập tin “pack idx” cho “%s”"
 
 #: builtin/index-pack.c:1448
 #, c-format
@@ -5175,7 +5219,7 @@ msgstr "--fix-thin không thể được dùng mà không có --stdin"
 #: builtin/index-pack.c:1563 builtin/index-pack.c:1573
 #, c-format
 msgid "packfile name '%s' does not end with '.pack'"
-msgstr "tên tập tin packfile `%s' không được kết thúc bằng đuôi '.pack'"
+msgstr "tên tập tin packfile “%s” không được kết thúc bằng đuôi “.pack”"
 
 #: builtin/index-pack.c:1582
 msgid "--verify with no packfile name given"
@@ -5194,22 +5238,22 @@ msgstr "tên mẫu dài một cách điên rồ %s"
 #: builtin/init-db.c:67
 #, c-format
 msgid "cannot stat '%s'"
-msgstr "không thể lấy trạng thái (stat) về `%s'"
+msgstr "không thể lấy trạng thái (stat) về “%s”"
 
 #: builtin/init-db.c:73
 #, c-format
 msgid "cannot stat template '%s'"
-msgstr "không thể stat (lấy trạng thái về) mẫu `%s'"
+msgstr "không thể stat (lấy trạng thái về) mẫu “%s”"
 
 #: builtin/init-db.c:80
 #, c-format
 msgid "cannot opendir '%s'"
-msgstr "không thể opendir `%s'"
+msgstr "không thể opendir “%s”"
 
 #: builtin/init-db.c:97
 #, c-format
 msgid "cannot readlink '%s'"
-msgstr "không thể readlink `%s'"
+msgstr "không thể readlink “%s”"
 
 #: builtin/init-db.c:99
 #, c-format
@@ -5219,7 +5263,7 @@ msgstr "liên kết tượng trưng dài một cách điên rồ %s"
 #: builtin/init-db.c:102
 #, c-format
 msgid "cannot symlink '%s' '%s'"
-msgstr "không thể tạo liên kết tượng trưng (symlink) `%s' `%s'"
+msgstr "không thể tạo liên kết tượng trưng (symlink) “%s” “%s”"
 
 #: builtin/init-db.c:106
 #, c-format
@@ -5244,7 +5288,7 @@ msgstr "các mẫu không được tìm thấy %s"
 #: builtin/init-db.c:154
 #, c-format
 msgid "not copying templates of a wrong format version %d from '%s'"
-msgstr "không sao chép các mẫu của phiên bản sai định dạng %d từ `%s'"
+msgstr "không sao chép các mẫu của phiên bản sai định dạng %d từ “%s”"
 
 #: builtin/init-db.c:192
 #, c-format
@@ -5269,7 +5313,7 @@ msgstr "không di chuyển được %s vào %s"
 #: builtin/init-db.c:363
 #, c-format
 msgid "Could not create git link %s"
-msgstr "Không thể tạo liên kết git `%s'"
+msgstr "Không thể tạo liên kết git “%s”"
 
 #.
 #. * TRANSLATORS: The first '%s' is either "Reinitialized
@@ -5343,7 +5387,7 @@ msgstr "Không thể truy cập thư mục làm việc hiện hành"
 #: builtin/init-db.c:586
 #, c-format
 msgid "Cannot access work tree '%s'"
-msgstr "không thể truy cập cây (tree) làm việc `%s'"
+msgstr "không thể truy cập cây (tree) làm việc “%s”"
 
 #: builtin/log.c:37
 msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
@@ -5370,213 +5414,213 @@ msgstr "các tùy chọn trang trí"
 msgid "Final output: %d %s\n"
 msgstr "Kết xuất cuối cùng: %d %s\n"
 
-#: builtin/log.c:403 builtin/log.c:494
+#: builtin/log.c:405 builtin/log.c:497
 #, c-format
 msgid "Could not read object %s"
 msgstr "Không thể đọc đối tượng %s"
 
-#: builtin/log.c:518
+#: builtin/log.c:521
 #, c-format
 msgid "Unknown type: %d"
 msgstr "Không nhận ra kiểu: %d"
 
-#: builtin/log.c:608
+#: builtin/log.c:613
 msgid "format.headers without value"
 msgstr "format.headers không có giá trị cụ thể"
 
-#: builtin/log.c:682
+#: builtin/log.c:687
 msgid "name of output directory is too long"
 msgstr "tên của thư mục kết xuất quá dài"
 
-#: builtin/log.c:693
+#: builtin/log.c:698
 #, c-format
 msgid "Cannot open patch file %s"
 msgstr "Không thể mở tập tin miếng vá: %s"
 
-#: builtin/log.c:707
+#: builtin/log.c:712
 msgid "Need exactly one range."
 msgstr "Cần chính xác một vùng."
 
-#: builtin/log.c:715
+#: builtin/log.c:720
 msgid "Not a range."
 msgstr "Không phải là một vùng."
 
-#: builtin/log.c:789
+#: builtin/log.c:794
 msgid "Cover letter needs email format"
-msgstr "'Cover letter' cần cho định dạng thư"
+msgstr "”Cover letter” cần cho định dạng thư"
 
-#: builtin/log.c:862
+#: builtin/log.c:867
 #, c-format
 msgid "insane in-reply-to: %s"
 msgstr "in-reply-to điên rồ: %s"
 
-#: builtin/log.c:890
+#: builtin/log.c:895
 msgid "git format-patch [options] [<since> | <revision range>]"
 msgstr "git format-patch [các-tùy-chọn] [<kể-từ> | <vùng-xem-xét>]"
 
-#: builtin/log.c:935
+#: builtin/log.c:940
 msgid "Two output directories?"
 msgstr "Hai thư mục kết xuất?"
 
-#: builtin/log.c:1063
+#: builtin/log.c:1068
 msgid "use [PATCH n/m] even with a single patch"
 msgstr "dùng [PATCH n/m] ngay cả với miếng vá đơn"
 
-#: builtin/log.c:1066
+#: builtin/log.c:1071
 msgid "use [PATCH] even with multiple patches"
 msgstr "dùng [VÁ] ngay cả với các miếng vá phức tạp"
 
-#: builtin/log.c:1070
+#: builtin/log.c:1075
 msgid "print patches to standard out"
 msgstr "hiển thị miếng vá ra đầu ra chuẩn"
 
-#: builtin/log.c:1072
+#: builtin/log.c:1077
 msgid "generate a cover letter"
 msgstr "tạo bì thư"
 
-#: builtin/log.c:1074
+#: builtin/log.c:1079
 msgid "use simple number sequence for output file names"
 msgstr "sử dụng chỗi dãy số dạng đơn giản cho tên tập-tin xuất ra"
 
-#: builtin/log.c:1075
+#: builtin/log.c:1080
 msgid "sfx"
 msgstr "sfx"
 
-#: builtin/log.c:1076
+#: builtin/log.c:1081
 msgid "use <sfx> instead of '.patch'"
-msgstr "sử dụng <sfx> thay cho '.patch'"
+msgstr "sử dụng <sfx> thay cho “.patch”"
 
-#: builtin/log.c:1078
+#: builtin/log.c:1083
 msgid "start numbering patches at <n> instead of 1"
 msgstr "bắt đầu đánh số miếng vá từ <n> thay vì 1"
 
-#: builtin/log.c:1080
+#: builtin/log.c:1085
 msgid "Use [<prefix>] instead of [PATCH]"
 msgstr "Dùng [<tiền-tố>] thay cho [VÁ]"
 
-#: builtin/log.c:1083
+#: builtin/log.c:1088
 msgid "store resulting files in <dir>"
 msgstr "lưu các tập tin kết quả trong <t.mục>"
 
-#: builtin/log.c:1086
+#: builtin/log.c:1091
 msgid "don't strip/add [PATCH]"
 msgstr "không strip/add [VÁ]"
 
-#: builtin/log.c:1089
+#: builtin/log.c:1094
 msgid "don't output binary diffs"
 msgstr "không kết xuất diff (những khác biệt) nhị phân"
 
-#: builtin/log.c:1091
+#: builtin/log.c:1096
 msgid "don't include a patch matching a commit upstream"
 msgstr "không bao gồm miếng vá khớp với một lần chuyển giao thượng nguồn"
 
-#: builtin/log.c:1093
+#: builtin/log.c:1098
 msgid "show patch format instead of default (patch + stat)"
 msgstr "hiển thị định dạng miếng vá thay vì mặc định (miếng vá + thống kê)"
 
-#: builtin/log.c:1095
+#: builtin/log.c:1100
 msgid "Messaging"
 msgstr "Lời nhắn"
 
-#: builtin/log.c:1096
+#: builtin/log.c:1101
 msgid "header"
 msgstr "đầu đề thư"
 
-#: builtin/log.c:1097
+#: builtin/log.c:1102
 msgid "add email header"
 msgstr "thêm đầu đề thư"
 
-#: builtin/log.c:1098 builtin/log.c:1100
+#: builtin/log.c:1103 builtin/log.c:1105
 msgid "email"
 msgstr "thư điện tử"
 
-#: builtin/log.c:1098
+#: builtin/log.c:1103
 msgid "add To: header"
 msgstr "thêm To: đầu đề thư"
 
-#: builtin/log.c:1100
+#: builtin/log.c:1105
 msgid "add Cc: header"
 msgstr "thêm Cc: đầu đề thư"
 
-#: builtin/log.c:1102
+#: builtin/log.c:1107
 msgid "message-id"
 msgstr "message-id"
 
-#: builtin/log.c:1103
+#: builtin/log.c:1108
 msgid "make first mail a reply to <message-id>"
 msgstr "dùng thư đầu tiên để trả lời <message-id>"
 
-#: builtin/log.c:1104 builtin/log.c:1107
+#: builtin/log.c:1109 builtin/log.c:1112
 msgid "boundary"
 msgstr "ranh giới"
 
-#: builtin/log.c:1105
+#: builtin/log.c:1110
 msgid "attach the patch"
 msgstr "đính kèm miếng vá"
 
-#: builtin/log.c:1108
+#: builtin/log.c:1113
 msgid "inline the patch"
 msgstr "dùng miếng vá làm nội dung"
 
-#: builtin/log.c:1112
+#: builtin/log.c:1117
 msgid "enable message threading, styles: shallow, deep"
-msgstr "cho phép luồng lời nhắn, kiểu: `shallow', `deep'"
+msgstr "cho phép luồng lời nhắn, kiểu: “shallow”, “deep”"
 
-#: builtin/log.c:1114
+#: builtin/log.c:1119
 msgid "signature"
 msgstr "chữ ký"
 
-#: builtin/log.c:1115
+#: builtin/log.c:1120
 msgid "add a signature"
 msgstr "thêm chữ ký"
 
-#: builtin/log.c:1117
+#: builtin/log.c:1122
 msgid "don't print the patch filenames"
 msgstr "không hiển thị các tên tập tin của miếng vá"
 
-#: builtin/log.c:1157
+#: builtin/log.c:1163
 #, c-format
 msgid "bogus committer info %s"
 msgstr "thông tin người chuyển giao không có thực %s"
 
-#: builtin/log.c:1202
+#: builtin/log.c:1208
 msgid "-n and -k are mutually exclusive."
 msgstr "-n và  -k loại từ lẫn nhau."
 
-#: builtin/log.c:1204
+#: builtin/log.c:1210
 msgid "--subject-prefix and -k are mutually exclusive."
 msgstr "--subject-prefix và -k xung khắc nhau."
 
-#: builtin/log.c:1212
+#: builtin/log.c:1218
 msgid "--name-only does not make sense"
 msgstr "--name-only không hợp lý"
 
-#: builtin/log.c:1214
+#: builtin/log.c:1220
 msgid "--name-status does not make sense"
 msgstr "--name-status không hợp lý"
 
-#: builtin/log.c:1216
+#: builtin/log.c:1222
 msgid "--check does not make sense"
 msgstr "--check không hợp lý"
 
-#: builtin/log.c:1239
+#: builtin/log.c:1245
 msgid "standard output, or directory, which one?"
 msgstr "đầu ra chuẩn, hay thư mục, chọn cái nào?"
 
-#: builtin/log.c:1241
+#: builtin/log.c:1247
 #, c-format
 msgid "Could not create directory '%s'"
-msgstr "Không thể tạo thư mục `%s'"
+msgstr "Không thể tạo thư mục “%s”"
 
-#: builtin/log.c:1394
+#: builtin/log.c:1400
 msgid "Failed to create output files"
 msgstr "Gặp lỗi khi tạo các tập tin kết xuất"
 
-#: builtin/log.c:1443
+#: builtin/log.c:1449
 msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
 msgstr "git cherry [-v] [<thượng-nguồn> [<head> [<giới-hạn>]]]"
 
-#: builtin/log.c:1498
+#: builtin/log.c:1504
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -5584,7 +5628,7 @@ msgstr ""
 "Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <thượng-nguồn> một cách "
 "thủ công.\n"
 
-#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525
+#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531
 #, c-format
 msgid "Unknown commit %s"
 msgstr "Không hiểu lần chuyển giao (commit) %s"
@@ -5600,7 +5644,7 @@ msgstr "nhận dạng các trạng thái tập tin với thẻ"
 #: builtin/ls-files.c:465
 msgid "use lowercase letters for 'assume unchanged' files"
 msgstr ""
-"dùng chữ cái viết thường cho các tập tin 'assume unchanged' (giả định không "
+"dùng chữ cái viết thường cho các tập tin “assume unchanged” (giả định không "
 "thay đổi)"
 
 #: builtin/ls-files.c:467
@@ -5633,7 +5677,7 @@ msgstr "hiển thị các tập tin trên hệ thống tập tin mà nó cần 
 
 #: builtin/ls-files.c:482
 msgid "show 'other' directories' name only"
-msgstr "chỉ hiển thị tên của các thư mục 'khác'"
+msgstr "chỉ hiển thị tên của các thư mục “khác”"
 
 #: builtin/ls-files.c:485
 msgid "don't show empty directories"
@@ -5739,7 +5783,7 @@ msgstr "switch `m' yêu cầu một giá trị"
 #: builtin/merge.c:127
 #, c-format
 msgid "Could not find merge strategy '%s'.\n"
-msgstr "Không tìm thấy chiến lược hòa trộn `%s'.\n"
+msgstr "Không tìm thấy chiến lược hòa trộn “%s”.\n"
 
 #: builtin/merge.c:128
 #, c-format
@@ -5854,7 +5898,7 @@ msgstr "Không thông điệp hòa trộn -- không cập nhật HEAD\n"
 #: builtin/merge.c:436
 #, c-format
 msgid "'%s' does not point to a commit"
-msgstr "`%s' không chỉ đến một lần chuyển giao (commit) nào cả"
+msgstr "“%s” không chỉ đến một lần chuyển giao (commit) nào cả"
 
 #: builtin/merge.c:535
 #, c-format
@@ -5865,37 +5909,33 @@ msgstr "Chuỗi branch.%s.mergeoptions sai: %s"
 msgid "git write-tree failed to write a tree"
 msgstr "lệnh git write-tree gặp lỗi khi ghi một cây"
 
-#: builtin/merge.c:678
-msgid "failed to read the cache"
-msgstr "gặp lỗi khi đọc bộ nhớ tạm"
-
-#: builtin/merge.c:709
+#: builtin/merge.c:656
 msgid "Not handling anything other than two heads merge."
 msgstr "Không cầm nắm gì ngoài hai head hòa trộn"
 
-#: builtin/merge.c:723
+#: builtin/merge.c:670
 #, c-format
 msgid "Unknown option for merge-recursive: -X%s"
 msgstr "Không hiểu tùy chọn cho merge-recursive: -X%s"
 
-#: builtin/merge.c:737
+#: builtin/merge.c:684
 #, c-format
 msgid "unable to write %s"
 msgstr "không thể ghi %s"
 
-#: builtin/merge.c:876
+#: builtin/merge.c:773
 #, c-format
 msgid "Could not read from '%s'"
-msgstr "Không thể đọc từ `%s'"
+msgstr "Không thể đọc từ “%s”"
 
-#: builtin/merge.c:885
+#: builtin/merge.c:782
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
-"Vẫn chưa hòa trộn các lần chuyển giao (commit); sử dụng lệnh `git commit' để "
+"Vẫn chưa hòa trộn các lần chuyển giao (commit); sử dụng lệnh “git commit” để "
 "hoàn tất việc hòa trộn.\n"
 
-#: builtin/merge.c:891
+#: builtin/merge.c:788
 msgid ""
 "Please enter a commit message to explain why this merge is necessary,\n"
 "especially if it merges an updated upstream into a topic branch.\n"
@@ -5908,59 +5948,59 @@ msgstr ""
 "đặc biệt là khi nó hòa trộn thượng nguồn đã cập nhật vào trong một nhánh "
 "topic.\n"
 "\n"
-"Những dòng được bắt đầu bằng '#' sẽ được bỏ qua, và phần chú thích này nếu "
+"Những dòng được bắt đầu bằng “#” sẽ được bỏ qua, và phần chú thích này nếu "
 "rỗng\n"
 "sẽ làm hủy bỏ lần chuyển giao (commit).\n"
 
-#: builtin/merge.c:915
+#: builtin/merge.c:812
 msgid "Empty commit message."
 msgstr "Chú thích của lần commit (chuyển giao) bị trống rỗng."
 
-#: builtin/merge.c:927
+#: builtin/merge.c:824
 #, c-format
 msgid "Wonderful.\n"
 msgstr "Thần kỳ.\n"
 
-#: builtin/merge.c:992
+#: builtin/merge.c:889
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
 "Việc tự động hòa trộn gặp lỗi; hãy sửa các xung đột sau đó chuyển giao "
 "(commit) kết quả.\n"
 
-#: builtin/merge.c:1008
+#: builtin/merge.c:905
 #, c-format
 msgid "'%s' is not a commit"
 msgstr "%s không phải là một lần commit (chuyển giao)"
 
-#: builtin/merge.c:1049
+#: builtin/merge.c:946
 msgid "No current branch."
 msgstr "không phải nhánh hiện hành"
 
-#: builtin/merge.c:1051
+#: builtin/merge.c:948
 msgid "No remote for the current branch."
 msgstr "Không có máy chủ cho nhánh hiện hành."
 
-#: builtin/merge.c:1053
+#: builtin/merge.c:950
 msgid "No default upstream defined for the current branch."
 msgstr "Không có thượng nguồn mặc định được định nghĩa cho nhánh hiện hành."
 
-#: builtin/merge.c:1058
+#: builtin/merge.c:955
 #, c-format
 msgid "No remote tracking branch for %s from %s"
 msgstr "Không nhánh mạng theo vết cho %s từ %s"
 
-#: builtin/merge.c:1145 builtin/merge.c:1302
+#: builtin/merge.c:1042 builtin/merge.c:1199
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - không phải là một số thứ chúng tôi có thể hòa trộn"
 
-#: builtin/merge.c:1213
+#: builtin/merge.c:1110
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr ""
 "Ở đây không có lần hòa trộn nào được hủy bỏ giữa chừng cả (thiếu MERGE_HEAD)."
 
-#: builtin/merge.c:1229 git-pull.sh:31
+#: builtin/merge.c:1126 git-pull.sh:31
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -5968,11 +6008,11 @@ msgstr ""
 "Bạn chưa kết thúc việc hòa trộng (MERGE_HEAD vẫn tồn tại).\n"
 "Hãy chuyển giao (commit) các thay đổi trước khi bạn có thể hòa trộn."
 
-#: builtin/merge.c:1232 git-pull.sh:34
+#: builtin/merge.c:1129 git-pull.sh:34
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "Bạn chưa kết thúc việc hòa trộng (MERGE_HEAD vẫn tồn tại)."
 
-#: builtin/merge.c:1236
+#: builtin/merge.c:1133
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you can merge."
@@ -5980,85 +6020,85 @@ msgstr ""
 "Bạn chưa kết thúc việc cherry-pick (CHERRY_PICK_HEAD vẫn tồn tại).\n"
 "Hãy chuyển giao (commit) các thay đổi trước khi bạn có thể hòa trộn."
 
-#: builtin/merge.c:1239
+#: builtin/merge.c:1136
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
 msgstr "Bạn chưa kết thúc việc cherry-pick (CHERRY_PICK_HEAD vẫn tồn tại)."
 
-#: builtin/merge.c:1248
+#: builtin/merge.c:1145
 msgid "You cannot combine --squash with --no-ff."
 msgstr "Bạn không thể kết hợp --squash với --no-ff."
 
-#: builtin/merge.c:1253
+#: builtin/merge.c:1150
 msgid "You cannot combine --no-ff with --ff-only."
 msgstr "Bạn không thể kết hợp --no-ff với --ff-only."
 
-#: builtin/merge.c:1260
+#: builtin/merge.c:1157
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr ""
 "Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được "
 "đặt."
 
-#: builtin/merge.c:1292
+#: builtin/merge.c:1189
 msgid "Can merge only exactly one commit into empty head"
 msgstr ""
 "Không thể hòa trộn một cách đúng đắn một lần chuyển giao (commit) vào một "
 "head rỗng"
 
-#: builtin/merge.c:1295
+#: builtin/merge.c:1192
 msgid "Squash commit into empty head not supported yet"
 msgstr "Squash commit vào một head trống rỗng vẫn chưa được hỗ trợ"
 
-#: builtin/merge.c:1297
+#: builtin/merge.c:1194
 msgid "Non-fast-forward commit does not make sense into an empty head"
 msgstr ""
 "Chuyển giao (commit) không-fast-forward không hợp lý ở trong một head trống "
 "rỗng"
 
-#: builtin/merge.c:1412
+#: builtin/merge.c:1309
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Đang cập nhật %s..%s\n"
 
-#: builtin/merge.c:1450
+#: builtin/merge.c:1348
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
-msgstr "Đang thử hòa trộn kiểu 'trivial in-index'...\n"
+msgstr "Đang thử hòa trộn kiểu “trivial in-index”...\n"
 
-#: builtin/merge.c:1457
+#: builtin/merge.c:1355
 #, c-format
 msgid "Nope.\n"
 msgstr "Không.\n"
 
-#: builtin/merge.c:1489
+#: builtin/merge.c:1387
 msgid "Not possible to fast-forward, aborting."
 msgstr "Thực hiện lệnh fast-forward là không thể được, đang bỏ qua."
 
-#: builtin/merge.c:1512 builtin/merge.c:1591
+#: builtin/merge.c:1410 builtin/merge.c:1489
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Đang tua lại cây thành thời xa xưa...\n"
 
-#: builtin/merge.c:1516
+#: builtin/merge.c:1414
 #, c-format
 msgid "Trying merge strategy %s...\n"
 msgstr "Đang thử chiến lược hòa trộn %s...\n"
 
-#: builtin/merge.c:1582
+#: builtin/merge.c:1480
 #, c-format
 msgid "No merge strategy handled the merge.\n"
 msgstr "Không có chiến lược hòa trộn nào được nắm giữ (handle) sự hòa trộn.\n"
 
-#: builtin/merge.c:1584
+#: builtin/merge.c:1482
 #, c-format
 msgid "Merge with strategy %s failed.\n"
 msgstr "Hòa trộn với chiến lược %s gặp lỗi.\n"
 
-#: builtin/merge.c:1593
+#: builtin/merge.c:1491
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
 msgstr "Sử dụng %s để chuẩn bị giải quyết bằng tay.\n"
 
-#: builtin/merge.c:1605
+#: builtin/merge.c:1503
 #, c-format
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
@@ -6091,7 +6131,7 @@ msgstr "tìm tổ tiên của hòa trộn n-way đơn"
 
 #: builtin/merge-base.c:100
 msgid "list revs not reachable from others"
-msgstr "liệt kê các 'rev' mà nó không thể đọc được từ cái khác"
+msgstr "liệt kê các “rev” mà nó không thể đọc được từ cái khác"
 
 #: builtin/merge-base.c:102
 msgid "is the first one ancestor of the other?"
@@ -6168,7 +6208,7 @@ msgstr "bỏ qua các lỗi liên quan đến di chuyển, đổi tên"
 #: builtin/mv.c:108
 #, c-format
 msgid "Checking rename of '%s' to '%s'\n"
-msgstr "Đang kiểm tra việc đổi tên của `%s' thành `%s'\n"
+msgstr "Đang kiểm tra việc đổi tên của “%s” thành “%s”\n"
 
 #: builtin/mv.c:112
 msgid "bad source"
@@ -6202,7 +6242,7 @@ msgstr "đích đã tồn tại sẵn rồi"
 #: builtin/mv.c:181
 #, c-format
 msgid "overwriting '%s'"
-msgstr "đang ghi đè lên `%s'"
+msgstr "đang ghi đè lên “%s”"
 
 #: builtin/mv.c:184
 msgid "Cannot overwrite"
@@ -6262,7 +6302,7 @@ msgstr "đọc từ đầu vào tiêu chuẩn"
 
 #: builtin/name-rev.c:236
 msgid "allow to print `undefined` names"
-msgstr "cho phép hiển thị các tên `chưa định nghĩa'"
+msgstr "cho phép hiển thị các tên `chưa định nghĩa`"
 
 #: builtin/notes.c:26
 msgid "git notes [--ref <notes_ref>] [list [<object>]]"
@@ -6377,26 +6417,26 @@ msgstr "git notes get-ref"
 #: builtin/notes.c:142
 #, c-format
 msgid "unable to start 'show' for object '%s'"
-msgstr "không thể khởi chạy 'show' cho đối tượng `%s'"
+msgstr "không thể khởi chạy “show” cho đối tượng “%s”"
 
 #: builtin/notes.c:148
 msgid "can't fdopen 'show' output fd"
-msgstr "không thể fdopen 'show' (lệnh hiển thị) mô tả tập tin (fd) kết xuất"
+msgstr "không thể fdopen “show” (lệnh hiển thị) mô tả tập tin (fd) kết xuất"
 
 #: builtin/notes.c:158
 #, c-format
 msgid "failed to close pipe to 'show' for object '%s'"
-msgstr "gặp lỗi khi đóng đường ống cho lệnh 'show' cho đối tượng `%s'"
+msgstr "gặp lỗi khi đóng đường ống cho lệnh “show” cho đối tượng “%s”"
 
 #: builtin/notes.c:161
 #, c-format
 msgid "failed to finish 'show' for object '%s'"
-msgstr "gặp lỗi khi hoàn thành `show' cho đối tượng `%s'"
+msgstr "gặp lỗi khi hoàn thành “show” cho đối tượng “%s”"
 
 #: builtin/notes.c:178 builtin/tag.c:347
 #, c-format
 msgid "could not create file '%s'"
-msgstr "không thể tạo tập tin `%s'"
+msgstr "không thể tạo tập tin “%s”"
 
 #: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
@@ -6420,12 +6460,12 @@ msgstr "Nội dung ghi chú còn lại %s"
 #: builtin/notes.c:254 builtin/tag.c:542
 #, c-format
 msgid "cannot read '%s'"
-msgstr "không thể đọc `%s'"
+msgstr "không thể đọc “%s”"
 
 #: builtin/notes.c:256 builtin/tag.c:545
 #, c-format
 msgid "could not open or read '%s'"
-msgstr "không thể mở để đọc hay ghi `%s'"
+msgstr "không thể mở để đọc hay ghi “%s”"
 
 #: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450
 #: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647
@@ -6433,12 +6473,12 @@ msgstr "không thể mở để đọc hay ghi `%s'"
 #: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
-msgstr "Gặp lỗi khi giải quyết `%s' như là một tham chiếu (ref) hợp lệ."
+msgstr "Gặp lỗi khi giải quyết “%s” như là một tham chiếu (ref) hợp lệ."
 
 #: builtin/notes.c:278
 #, c-format
 msgid "Failed to read object '%s'."
-msgstr "Gặp lỗi khi đọc đối tượng `%s'."
+msgstr "Gặp lỗi khi đọc đối tượng “%s”."
 
 #: builtin/notes.c:302
 msgid "Cannot commit uninitialized/unreferenced notes tree"
@@ -6449,7 +6489,7 @@ msgstr ""
 #: builtin/notes.c:343
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
-msgstr "Giá trị notes.rewriteMode sai: `%s'"
+msgstr "Giá trị notes.rewriteMode sai: “%s”"
 
 #: builtin/notes.c:353
 #, c-format
@@ -6461,17 +6501,17 @@ msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoài của refs/notes/)"
 #: builtin/notes.c:380
 #, c-format
 msgid "Bad %s value: '%s'"
-msgstr "Giá trị %s sai: `%s'"
+msgstr "Giá trị %s sai: “%s”"
 
 #: builtin/notes.c:444
 #, c-format
 msgid "Malformed input line: '%s'."
-msgstr "Dòng nhập vào dị hình: `%s'."
+msgstr "Dòng nhập vào dị hình: “%s”."
 
 #: builtin/notes.c:459
 #, c-format
 msgid "Failed to copy notes from '%s' to '%s'"
-msgstr "Gặp lỗi khi sao chép ghi chú (note) từ `%s' tới `%s'"
+msgstr "Gặp lỗi khi sao chép ghi chú (note) từ “%s” tới “%s”"
 
 #: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630
 #: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762
@@ -6516,7 +6556,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Không thể thêm các ghi chú. Đã tìm thấy các ghi chú đã có sẵn cho đối tượng "
-"%s. Sử dụng tùy chọn '-f' để ghi đè lên các ghi chú cũ"
+"%s. Sử dụng tùy chọn “-f” để ghi đè lên các ghi chú cũ"
 
 #: builtin/notes.c:588 builtin/notes.c:665
 #, c-format
@@ -6542,7 +6582,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Không thể sao chép các ghi chú. Đã tìm thấy các ghi chú đã có sẵn cho đối "
-"tượng %s. Sử dụng tùy chọn '-f' để ghi đè lên các ghi chú cũ"
+"tượng %s. Sử dụng tùy chọn “-f” để ghi đè lên các ghi chú cũ"
 
 #: builtin/notes.c:671
 #, c-format
@@ -6555,8 +6595,8 @@ msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
 "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
 msgstr ""
-"Các tùy chọn -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con `edit'.\n"
-"Xin hãy sử dụng lệnh sau để thay thế: `git notes add -f -m/-F/-c/-C'.\n"
+"Các tùy chọn -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con “edit”.\n"
+"Xin hãy sử dụng lệnh sau để thay thế: “git notes add -f -m/-F/-c/-C”.\n"
 
 #: builtin/notes.c:867
 msgid "General options"
@@ -6571,7 +6611,7 @@ msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
 "cat_sort_uniq)"
 msgstr ""
-"phân giải các xung đột `notes' sử dụng chiến lược đã đưa ra (manual/ours/"
+"phân giải các xung đột “notes” sử dụng chiến lược đã đưa ra (manual/ours/"
 "theirs/union/cat_sort_uniq)"
 
 #: builtin/notes.c:873
@@ -6611,7 +6651,7 @@ msgstr "notes_ref"
 
 #: builtin/notes.c:1071
 msgid "use notes from <notes_ref>"
-msgstr "dùng `notes' từ <notes_ref>"
+msgstr "dùng “notes” từ <notes_ref>"
 
 #: builtin/notes.c:1106 builtin/remote.c:1598
 #, c-format
@@ -6635,146 +6675,146 @@ msgstr ""
 msgid "deflate error (%d)"
 msgstr "lỗi giải nén (%d)"
 
-#: builtin/pack-objects.c:2398
+#: builtin/pack-objects.c:2397
 #, c-format
 msgid "unsupported index version %s"
 msgstr "phiên bản mục lục không được hỗ trợ %s"
 
-#: builtin/pack-objects.c:2402
+#: builtin/pack-objects.c:2401
 #, c-format
 msgid "bad index version '%s'"
-msgstr "phiên bản mục lục sai `%s'"
+msgstr "phiên bản mục lục sai “%s”"
 
-#: builtin/pack-objects.c:2425
+#: builtin/pack-objects.c:2424
 #, c-format
 msgid "option %s does not accept negative form"
 msgstr "tùy chọn %s không chấp nhận dạng thức âm"
 
-#: builtin/pack-objects.c:2429
+#: builtin/pack-objects.c:2428
 #, c-format
 msgid "unable to parse value '%s' for option %s"
-msgstr "không thể phân tích giá trị `%s' cho tùy chọn %s"
+msgstr "không thể phân tích giá trị “%s” cho tùy chọn %s"
 
-#: builtin/pack-objects.c:2448
+#: builtin/pack-objects.c:2447
 msgid "do not show progress meter"
 msgstr "không hiển thị bộ đo tiến trình"
 
-#: builtin/pack-objects.c:2450
+#: builtin/pack-objects.c:2449
 msgid "show progress meter"
 msgstr "hiển thị bộ đo tiến trình"
 
-#: builtin/pack-objects.c:2452
+#: builtin/pack-objects.c:2451
 msgid "show progress meter during object writing phase"
 msgstr "hiển thị bộ đo tiến triển trong suốt pha ghi đối tượng"
 
-#: builtin/pack-objects.c:2455
+#: builtin/pack-objects.c:2454
 msgid "similar to --all-progress when progress meter is shown"
 msgstr "tương tự --all-progress khi bộ đo tiến trình được xuất hiện"
 
-#: builtin/pack-objects.c:2456
+#: builtin/pack-objects.c:2455
 msgid "version[,offset]"
 msgstr "phiên bản[,offset]"
 
-#: builtin/pack-objects.c:2457
+#: builtin/pack-objects.c:2456
 msgid "write the pack index file in the specified idx format version"
 msgstr "ghi tập tin bảng mục lục gói (pack) ở phiên bản định dạng idx đã cho"
 
-#: builtin/pack-objects.c:2460
+#: builtin/pack-objects.c:2459
 msgid "maximum size of each output pack file"
 msgstr "kcíh thước tối đa cho tập tin gói được tạo"
 
-#: builtin/pack-objects.c:2462
+#: builtin/pack-objects.c:2461
 msgid "ignore borrowed objects from alternate object store"
 msgstr "bỏ qua các đối tượng vay mượn từ kho đối tượng thay thế"
 
-#: builtin/pack-objects.c:2464
+#: builtin/pack-objects.c:2463
 msgid "ignore packed objects"
 msgstr "bỏ qua các đối tượng đóng gói"
 
-#: builtin/pack-objects.c:2466
+#: builtin/pack-objects.c:2465
 msgid "limit pack window by objects"
 msgstr "giới hạn cửa sổ đóng gói theo đối tượng"
 
-#: builtin/pack-objects.c:2468
+#: builtin/pack-objects.c:2467
 msgid "limit pack window by memory in addition to object limit"
 msgstr "giới hạn cửa sổ đóng gói theo bộ nhớ cộng thêm với giới hạn đối tượng"
 
-#: builtin/pack-objects.c:2470
+#: builtin/pack-objects.c:2469
 msgid "maximum length of delta chain allowed in the resulting pack"
-msgstr "độ dài tối đa của chuỗi móc xích `delta' được phép trong gói kết quả"
+msgstr "độ dài tối đa của chuỗi móc xích “delta” được phép trong gói kết quả"
 
-#: builtin/pack-objects.c:2472
+#: builtin/pack-objects.c:2471
 msgid "reuse existing deltas"
 msgstr "dùng lại các delta sẵn có"
 
-#: builtin/pack-objects.c:2474
+#: builtin/pack-objects.c:2473
 msgid "reuse existing objects"
 msgstr "dùng lại các đối tượng sẵn có"
 
-#: builtin/pack-objects.c:2476
+#: builtin/pack-objects.c:2475
 msgid "use OFS_DELTA objects"
 msgstr "dùng các đối tượng OFS_DELTA"
 
-#: builtin/pack-objects.c:2478
+#: builtin/pack-objects.c:2477
 msgid "use threads when searching for best delta matches"
 msgstr "sử dụng các tuyến trình khi tìm kiếm cho các mẫu khớp delta tốt nhất"
 
-#: builtin/pack-objects.c:2480
+#: builtin/pack-objects.c:2479
 msgid "do not create an empty pack output"
 msgstr "không thể tạo kết xuất gói (pack) trống rỗng"
 
-#: builtin/pack-objects.c:2482
+#: builtin/pack-objects.c:2481
 msgid "read revision arguments from standard input"
-msgstr " đọc tham số `revision' từ thiết bị nhập chuẩn"
+msgstr " đọc tham số “revision” từ thiết bị nhập chuẩn"
 
-#: builtin/pack-objects.c:2484
+#: builtin/pack-objects.c:2483
 msgid "limit the objects to those that are not yet packed"
 msgstr "giới hạn các đối tượng thành những cái mà chúng vẫn chưa được đóng gói"
 
-#: builtin/pack-objects.c:2487
+#: builtin/pack-objects.c:2486
 msgid "include objects reachable from any reference"
 msgstr "bao gồm các đối tượng có thể đọc được từ bất kỳ tham chiếu nào"
 
-#: builtin/pack-objects.c:2490
+#: builtin/pack-objects.c:2489
 msgid "include objects referred by reflog entries"
 msgstr "bao gồm các đối tượng được tham chiếu bởi các mục reflog"
 
-#: builtin/pack-objects.c:2493
+#: builtin/pack-objects.c:2492
 msgid "output pack to stdout"
 msgstr "xuất gói ra đầu ra tiêu chuẩn"
 
-#: builtin/pack-objects.c:2495
+#: builtin/pack-objects.c:2494
 msgid "include tag objects that refer to objects to be packed"
 msgstr "bao gồm các đối tượng tham chiếu đến các đối tượng được đóng gói"
 
-#: builtin/pack-objects.c:2497
+#: builtin/pack-objects.c:2496
 msgid "keep unreachable objects"
 msgstr "giữ lại các đối tượng không thể đọc được"
 
-#: builtin/pack-objects.c:2498 parse-options.h:141
+#: builtin/pack-objects.c:2497 parse-options.h:141
 msgid "time"
 msgstr "thời-gian"
 
-#: builtin/pack-objects.c:2499
+#: builtin/pack-objects.c:2498
 msgid "unpack unreachable objects newer than <time>"
 msgstr ""
 "xả nén (gỡ khỏi gói) các đối tượng không thể đọc được mới hơn <thời-gian>"
 
-#: builtin/pack-objects.c:2502
+#: builtin/pack-objects.c:2501
 msgid "create thin packs"
 msgstr "tạo gói nhẹ"
 
-#: builtin/pack-objects.c:2504
+#: builtin/pack-objects.c:2503
 msgid "ignore packs that have companion .keep file"
 msgstr "bỏ qua các gói mà nó có tập tin .keep đi kèm"
 
-#: builtin/pack-objects.c:2506
+#: builtin/pack-objects.c:2505
 msgid "pack compression level"
 msgstr "mức nén gói"
 
-#: builtin/pack-objects.c:2508
+#: builtin/pack-objects.c:2507
 msgid "do not hide commits by grafts"
-msgstr "không ẩn các lần chuyển giao bởi `grafts'"
+msgstr "không ẩn các lần chuyển giao bởi “grafts”"
 
 #: builtin/pack-refs.c:6
 msgid "git pack-refs [options]"
@@ -6826,8 +6866,8 @@ msgid ""
 "To choose either option permanently, see push.default in 'git help config'."
 msgstr ""
 "\n"
-"Để chọn mỗi tùy chọn một cách cố định, xem push.default trong `git help "
-"config'."
+"Để chọn mỗi tùy chọn một cách cố định, xem push.default trong git help "
+"config."
 
 #: builtin/push.c:102
 #, c-format
@@ -6895,9 +6935,9 @@ msgid ""
 "your current branch '%s', without telling me what to push\n"
 "to update which remote branch."
 msgstr ""
-"Bạn đang push (đẩy lên) máy chủ `%s', mà nó không phải là thượng nguồn "
+"Bạn đang push (đẩy lên) máy chủ “%s”, mà nó không phải là thượng nguồn "
 "(upstream) của\n"
-"nhánh hiện tại `%s' của bạn, mà không báo cho tôi biết là cái gì được push\n"
+"nhánh hiện tại “%s” của bạn, mà không báo cho tôi biết là cái gì được push\n"
 "để cập nhật nhánh máy chủ nào."
 
 #: builtin/push.c:151
@@ -6918,7 +6958,7 @@ msgid ""
 "'current' instead of 'simple' if you sometimes use older versions of Git)"
 msgstr ""
 "biến push.default chưa được đặt; giá trị ngầm định của nó\n"
-"đã được thay đổi trong Git 2.0 từ 'matching' thành 'simple'.\n"
+"đã được thay đổi trong Git 2.0 từ “matching” thành “simple”.\n"
 "Để không hiển thị nhắc nhở này và duy trì cách xử lý sau\n"
 "những thay đổi mặc định này, hãy chạy lệnh:\n"
 "\n"
@@ -6928,10 +6968,10 @@ msgstr ""
 "\n"
 "  git config --global push.default simple\n"
 "\n"
-"Xem `git help config' và tìm đến `push.default' để có thêm thông tin.\n"
-"(chế độ 'simple' được bắt đầu sử dụng từ Git 1.7.11. Sử dụng chế độ tương "
+"Xem “git help config” và tìm đến “push.default” để có thêm thông tin.\n"
+"(chế độ “simple” được bắt đầu sử dụng từ Git 1.7.11. Sử dụng chế độ tương "
 "tự\n"
-"`current' thay vì `simple' nếu bạn thỉnh thoảng phải sử dụng bản Git cũ)"
+"“current” thay vì “simple” nếu bạn thỉnh thoảng phải sử dụng bản Git cũ)"
 
 #: builtin/push.c:199
 msgid ""
@@ -6948,10 +6988,10 @@ msgid ""
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
-"phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ (v.d. `git "
-"pull')\n"
+"phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ (v.d. git "
+"pull)\n"
 "trước khi lại push lần nữa.\n"
-"Xem trong phần 'Note about fast-forwards' từ lệnh `git push --help' để có "
+"Xem trong phần “Note about fast-forwards” từ lệnh “git push --help” để có "
 "thông tin chi tiết."
 
 #: builtin/push.c:212
@@ -6964,9 +7004,9 @@ msgstr ""
 "Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
 "phận tương ứng của máy chủ. Nếu bạn không có ý định push nhánh đó, bạn có lẽ "
 "muốn\n"
-"chỉ định các nhánh để push hoặt là đặt nội dung cho biến cấu hình 'push."
-"default'\n"
-"thành 'simple', 'current' hoặc 'upstream' để chỉ push nhánh hiện hành mà "
+"chỉ định các nhánh để push hoặt là đặt nội dung cho biến cấu hình push."
+"default\n"
+"thành “simple”, “current” hoặc “upstream” để chỉ push nhánh hiện hành mà "
 "thôi."
 
 #: builtin/push.c:218
@@ -6979,8 +7019,8 @@ msgstr ""
 "Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
 "phận tương ứng của máy chủ. Checkou nhánh này và hòa trộn với các thay đổi "
 "từ máy chủ\n"
-"(v.d. `git pull') trước khi lại push lần nữa.\n"
-"Xem trong phần 'Note about fast-forwards' từ lệnh `git push --help' để có "
+"(v.d. “git pull”) trước khi lại push lần nữa.\n"
+"Xem trong phần “Note about fast-forwards” từ lệnh “git push --help” để có "
 "thông tin chi tiết."
 
 #: builtin/push.c:258
@@ -6991,12 +7031,12 @@ msgstr "Đang push (đẩy) lên %s\n"
 #: builtin/push.c:262
 #, c-format
 msgid "failed to push some refs to '%s'"
-msgstr "gặp lỗi khi push (đẩy lên) một số tham chiếu (ref) đến `%s'"
+msgstr "gặp lỗi khi push (đẩy lên) một số tham chiếu (ref) đến “%s”"
 
 #: builtin/push.c:294
 #, c-format
 msgid "bad repository '%s'"
-msgstr "repository (kho) sai `%s'"
+msgstr "repository (kho) sai “%s”"
 
 #: builtin/push.c:295
 msgid ""
@@ -7126,11 +7166,11 @@ msgstr "thực hiện một hòa trộn thêm vào việc đọc"
 #: builtin/read-tree.c:117
 msgid "3-way merge if no file level merging required"
 msgstr ""
-"hòa trộn kiểu `3-way' nếu không có tập tin mức hòa trộn nào được yêu cầu "
+"hòa trộn kiểu “3-way” nếu không có tập tin mức hòa trộn nào được yêu cầu "
 
 #: builtin/read-tree.c:119
 msgid "3-way merge in presence of adds and removes"
-msgstr "hòa trộn 3-way trong sự hiện diện của `adds' và `removes'"
+msgstr "hòa trộn 3-way trong sự hiện diện của “adds” và “removes”"
 
 #: builtin/read-tree.c:121
 msgid "same as -m, but discard unmerged entries"
@@ -7192,7 +7232,7 @@ msgstr "git remote rename <tên-cũ> <tên-mới>"
 msgid "git remote remove <name>"
 msgstr "git remote remove <tên>"
 
-#: builtin/remote.c:15
+#: builtin/remote.c:15 builtin/remote.c:42
 msgid "git remote set-head <name> (-a | -d | <branch>)"
 msgstr "git remote set-head <tên> (-a | -d | <nhánh>)"
 
@@ -7230,10 +7270,6 @@ msgstr "git remote set-url --delete <tên> <url>"
 msgid "git remote add [<options>] <name> <url>"
 msgstr "git remote add [<các-tùy-chọn>] <tên> <url>"
 
-#: builtin/remote.c:42
-msgid "git remote set-head <name> (-a | -d | <branch>])"
-msgstr "git remote set-head <tên> (-a | -d | <nhánh>])"
-
 #: builtin/remote.c:47
 msgid "git remote set-branches <name> <branch>..."
 msgstr "git remote set-branches <tên> <nhánh>..."
@@ -7307,7 +7343,7 @@ msgstr "đang chỉ định một nhánh master không hợp lý với tùy ch
 
 #: builtin/remote.c:187
 msgid "specifying branches to track makes sense only with fetch mirrors"
-msgstr "chỉ định những nhánh để theo vết chỉ hợp lý với các 'fetch mirror'"
+msgstr "chỉ định những nhánh để theo vết chỉ hợp lý với các “fetch mirror”"
 
 #: builtin/remote.c:195 builtin/remote.c:646
 #, c-format
@@ -7317,12 +7353,12 @@ msgstr "máy chủ %s đã tồn tại rồi."
 #: builtin/remote.c:199 builtin/remote.c:650
 #, c-format
 msgid "'%s' is not a valid remote name"
-msgstr "`%s' không phải tên máy chủ hợp lệ"
+msgstr "“%s” không phải tên máy chủ hợp lệ"
 
 #: builtin/remote.c:243
 #, c-format
 msgid "Could not setup master '%s'"
-msgstr "Không thể cài đặt nhánh master `%s'"
+msgstr "Không thể cài đặt nhánh master “%s”"
 
 #: builtin/remote.c:299
 #, c-format
@@ -7345,7 +7381,7 @@ msgstr "(xoá)"
 #: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
 #, c-format
 msgid "Could not append '%s' to '%s'"
-msgstr "Không thể nối thêm `%s' vào `%s'"
+msgstr "Không thể nối thêm “%s” vào “%s”"
 
 #: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
 #, c-format
@@ -7355,12 +7391,12 @@ msgstr "Không có máy chủ nào như thế: %s"
 #: builtin/remote.c:656
 #, c-format
 msgid "Could not rename config section '%s' to '%s'"
-msgstr "Không thể đổi tên chương (section) cấu hình từ `%s' thành `%s'"
+msgstr "Không thể đổi tên chương (section) cấu hình từ “%s” thành “%s”"
 
 #: builtin/remote.c:662 builtin/remote.c:799
 #, c-format
 msgid "Could not remove config section '%s'"
-msgstr "Không thể gỡ bỏ chương (section) cấu hình `%s'"
+msgstr "Không thể gỡ bỏ chương (section) cấu hình “%s”"
 
 #: builtin/remote.c:677
 #, c-format
@@ -7369,19 +7405,19 @@ msgid ""
 "\t%s\n"
 "\tPlease update the configuration manually if necessary."
 msgstr ""
-"Không cập nhật 'non-default fetch respec'\n"
+"Không cập nhật “non-default fetch respec”\n"
 "\t%s\n"
 "\tXin hãy cập nhật phần cấu hình một cách thủ công nếu thấy cần thiết."
 
 #: builtin/remote.c:683
 #, c-format
 msgid "Could not append '%s'"
-msgstr "Không thể nối thêm `%s'"
+msgstr "Không thể nối thêm “%s”"
 
 #: builtin/remote.c:694
 #, c-format
 msgid "Could not set '%s'"
-msgstr "Không thể đặt `%s'"
+msgstr "Không thể đặt “%s”"
 
 #: builtin/remote.c:716
 #, c-format
@@ -7424,7 +7460,7 @@ msgstr " được theo vết"
 
 #: builtin/remote.c:948
 msgid " stale (use 'git remote prune' to remove)"
-msgstr " cũ (dùng `git remote prune' để gỡ bỏ)"
+msgstr " cũ (dùng “git remote prune” để gỡ bỏ)"
 
 #: builtin/remote.c:950
 msgid " ???"
@@ -7546,19 +7582,19 @@ msgstr " (trạng thái không được yêu cầu)"
 #: builtin/remote.c:1163
 msgid "  Local branch configured for 'git pull':"
 msgid_plural "  Local branches configured for 'git pull':"
-msgstr[0] "  Nhánh nội bộ đã được cấu hình cho lệnh `git pull':"
-msgstr[1] "  Những nhánh nội bộ đã được cấu hình cho lệnh `git pull':"
+msgstr[0] "  Nhánh nội bộ đã được cấu hình cho lệnh “git pull”:"
+msgstr[1] "  Những nhánh nội bộ đã được cấu hình cho lệnh “git pull”:"
 
 #: builtin/remote.c:1171
 msgid "  Local refs will be mirrored by 'git push'"
-msgstr "  refs nội bộ sẽ được phản chiếu bởi lệnh `git push'"
+msgstr "  refs nội bộ sẽ được phản chiếu bởi lệnh “git push”"
 
 #: builtin/remote.c:1178
 #, c-format
 msgid "  Local ref configured for 'git push'%s:"
 msgid_plural "  Local refs configured for 'git push'%s:"
-msgstr[0] "  Tham chiếu nội bộ được cấu hình cho lệnh `git push'%s:"
-msgstr[1] "  Những tham chiếu nội bộ được cấu hình cho lệnh `git push'%s:"
+msgstr[0] "  Tham chiếu nội bộ được cấu hình cho lệnh “git push”%s:"
+msgstr[1] "  Những tham chiếu nội bộ được cấu hình cho lệnh “git push”%s:"
 
 #: builtin/remote.c:1199
 msgid "set refs/remotes/<name>/HEAD according to remote"
@@ -7628,7 +7664,7 @@ msgstr "cắt máy chủ sau khi lấy về"
 #: builtin/remote.c:1387 builtin/remote.c:1461
 #, c-format
 msgid "No such remote '%s'"
-msgstr "Không có máy chủ nào có tên `%s'"
+msgstr "Không có máy chủ nào có tên “%s”"
 
 #: builtin/remote.c:1407
 msgid "add branch"
@@ -7640,7 +7676,7 @@ msgstr "chưa chỉ ra máy chủ nào"
 
 #: builtin/remote.c:1436
 msgid "manipulate push URLs"
-msgstr "đẩy các `URL' bằng tay"
+msgstr "đẩy các “URL” bằng tay"
 
 #: builtin/remote.c:1438
 msgid "add URL"
@@ -7684,15 +7720,15 @@ msgstr "git replace -d <đối tượng>..."
 msgid "git replace -l [<pattern>]"
 msgstr "git replace -l [<mẫu>]"
 
-#: builtin/replace.c:118
+#: builtin/replace.c:121
 msgid "list replace refs"
 msgstr "liệt kê các refs thay thế"
 
-#: builtin/replace.c:119
+#: builtin/replace.c:122
 msgid "delete replace refs"
 msgstr "xóa tham chiếu (refs) thay thế"
 
-#: builtin/replace.c:120
+#: builtin/replace.c:123
 msgid "replace the ref if it exists"
 msgstr "thay thế tham chiếu (ref) nếu nó đã sẵn có"
 
@@ -7796,7 +7832,7 @@ msgstr "đặt lại HEAD nhưng giữ lại các thay đổi nội bộ"
 #: builtin/reset.c:303
 #, c-format
 msgid "Could not parse object '%s'."
-msgstr "không thể phân tích đối tượng `%s'."
+msgstr "không thể phân tích đối tượng “%s”."
 
 #: builtin/reset.c:308
 msgid "--patch is incompatible with --{hard,mixed,soft}"
@@ -7805,8 +7841,8 @@ msgstr "--patch xung khắc với --{hard,mixed,soft}"
 #: builtin/reset.c:317
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
 msgstr ""
-"--mixed với các đường dẫn không còn dùng nữa; hãy thay thế bằng lệnh `git "
-"reset -- <đường_dẫn>'."
+"--mixed với các đường dẫn không còn dùng nữa; hãy thay thế bằng lệnh git "
+"reset -- <đường_dẫn>."
 
 #: builtin/reset.c:319
 #, c-format
@@ -7821,7 +7857,7 @@ msgstr "%s reset không được phép trên kho bare (trên máy chủ)"
 #: builtin/reset.c:347
 #, c-format
 msgid "Could not reset index file to revision '%s'."
-msgstr "Không thể đặt lại (reset) bảng mục lục thành điểm xét lại `%s'."
+msgstr "Không thể đặt lại (reset) bảng mục lục thành điểm xét lại “%s”."
 
 #: builtin/rev-parse.c:339
 msgid "git rev-parse --parseopt [options] -- [<args>...]"
@@ -7829,7 +7865,7 @@ msgstr "git rev-parse --parseopt [các-tùy-chọn] -- [<th.số>...]"
 
 #: builtin/rev-parse.c:344
 msgid "keep the `--` passed as an arg"
-msgstr "giữ '--' chuyển qua làm tham số"
+msgstr "giữ `--` chuyển qua làm tham số"
 
 #: builtin/rev-parse.c:346
 msgid "stop parsing after the first non-option argument"
@@ -7938,63 +7974,73 @@ msgstr "revert gặp lỗi"
 msgid "cherry-pick failed"
 msgstr "cherry-pick gặp lỗi"
 
-#: builtin/rm.c:14
+#: builtin/rm.c:15
 msgid "git rm [options] [--] <file>..."
 msgstr "git rm [các-tùy-chọn] [--] <tập-tin>..."
 
-#: builtin/rm.c:109
+#: builtin/rm.c:64 builtin/rm.c:186
+#, c-format
+msgid ""
+"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"(use 'rm -rf' if you really want to remove it including all of its history)"
+msgstr ""
+"mô-đun-con '%s' (hoặc cái nằm trong các mô-đun-con) dùng thư mục .git\n"
+"(dùng 'rm -rf' nếu bạn thực sự muốn gỡ bỏ nó cùng với tất cả lịch sử của "
+"chúng)"
+
+#: builtin/rm.c:174
 #, c-format
 msgid ""
 "'%s' has staged content different from both the file and the HEAD\n"
 "(use -f to force removal)"
 msgstr ""
-"`%s' có nội dung được lưu trạng thái khác biệt từ cả tập tin và cả HEAD\n"
+"“%s” có nội dung được lưu trạng thái khác biệt từ cả tập tin và cả HEAD\n"
 "(dùng tùy chọn -f để ép buộc gỡ bỏ)"
 
-#: builtin/rm.c:115
+#: builtin/rm.c:180
 #, c-format
 msgid ""
 "'%s' has changes staged in the index\n"
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
-"`%s' có các thay đổi được lưu trạng thái trong bảng mục lục\n"
+"“%s” có các thay đổi được lưu trạng thái trong bảng mục lục\n"
 "(dùng tùy chọn --cached để giữ tập tin, hoặc -f để ép buộc gỡ bỏ)"
 
-#: builtin/rm.c:119
+#: builtin/rm.c:191
 #, c-format
 msgid ""
 "'%s' has local modifications\n"
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
-"`%s' có các thay đổi nội bộ\n"
+"“%s” có các thay đổi nội bộ\n"
 "(dùng tùy chọn --cached để giữ tập tin, hoặc -f để ép buộc gỡ bỏ)"
 
-#: builtin/rm.c:134
+#: builtin/rm.c:207
 msgid "do not list removed files"
 msgstr "không liệt kê các tập tin đã gỡ bỏ"
 
-#: builtin/rm.c:135
+#: builtin/rm.c:208
 msgid "only remove from the index"
 msgstr "chỉ gỡ bỏ từ mục lục"
 
-#: builtin/rm.c:136
+#: builtin/rm.c:209
 msgid "override the up-to-date check"
 msgstr "ghi đè lên kiểm tra cập nhật"
 
-#: builtin/rm.c:137
+#: builtin/rm.c:210
 msgid "allow recursive removal"
 msgstr "cho phép gỡ bỏ đệ qui"
 
-#: builtin/rm.c:139
+#: builtin/rm.c:212
 msgid "exit with a zero status even if nothing matched"
 msgstr "thoát ra với trạng thái khác không thậm chí nếu không có gì khớp"
 
-#: builtin/rm.c:194
+#: builtin/rm.c:283
 #, c-format
 msgid "not removing '%s' recursively without -r"
-msgstr "không thể gỡ bỏ `%s' một cách đệ qui mà không có tùy chọn -r"
+msgstr "không thể gỡ bỏ “%s” một cách đệ qui mà không có tùy chọn -r"
 
-#: builtin/rm.c:230
+#: builtin/rm.c:322
 #, c-format
 msgid "git rm: unable to remove %s"
 msgstr "git rm: không thể gỡ bỏ %s"
@@ -8054,7 +8100,7 @@ msgstr "hiển thị các nhánh remote-tracking"
 
 #: builtin/show-branch.c:655
 msgid "color '*!+-' corresponding to the branch"
-msgstr "màu '*!+-' tương ứng với nhánh"
+msgstr "màu “*!+-” tương ứng với nhánh"
 
 #: builtin/show-branch.c:657
 msgid "show <n> more commits after the common ancestor"
@@ -8106,7 +8152,7 @@ msgstr "<n>[,<cơ sở>]"
 
 #: builtin/show-branch.c:679
 msgid "show <n> most recent ref-log entries starting at base"
-msgstr "hiển thị <n> các mục `ref-log' gần nhất kể từ nền (base)"
+msgstr "hiển thị <n> các mục “ref-log” gần nhất kể từ nền (base)"
 
 #: builtin/show-ref.c:10
 msgid ""
@@ -8120,38 +8166,38 @@ msgstr ""
 msgid "git show-ref --exclude-existing[=pattern] < ref-list"
 msgstr "git show-ref --exclude-existing[=mẫu] < ref-list"
 
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:165
 msgid "only show tags (can be combined with heads)"
 msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng với đầu)"
 
-#: builtin/show-ref.c:183
+#: builtin/show-ref.c:166
 msgid "only show heads (can be combined with tags)"
 msgstr "chỉ hiển thị đầu (có thể tổ hợp cùng với thẻ)"
 
-#: builtin/show-ref.c:184
+#: builtin/show-ref.c:167
 msgid "stricter reference checking, requires exact ref path"
 msgstr ""
 "việc kiểm tra tham chiếu chính xác, đòi hỏi chính xác đường dẫn tham chiếu "
 "(ref)"
 
-#: builtin/show-ref.c:187 builtin/show-ref.c:189
+#: builtin/show-ref.c:170 builtin/show-ref.c:172
 msgid "show the HEAD reference"
 msgstr "hiển thị tham chiếu của HEAD"
 
-#: builtin/show-ref.c:191
+#: builtin/show-ref.c:174
 msgid "dereference tags into object IDs"
 msgstr "bãi bỏ tham chiếu các thẻ thành ra các ID đối tượng"
 
-#: builtin/show-ref.c:193
+#: builtin/show-ref.c:176
 msgid "only show SHA1 hash using <n> digits"
 msgstr "chỉ hiển thị mã băm SHA1 sử dụng <n> chữ số"
 
-#: builtin/show-ref.c:197
+#: builtin/show-ref.c:180
 msgid "do not print results to stdout (useful with --verify)"
 msgstr ""
 "không hiển thị kết quả ra đầu ra chuẩn (stdout) (chỉ hữu dụng với --verify)"
 
-#: builtin/show-ref.c:199
+#: builtin/show-ref.c:182
 msgid "show refs from stdin that aren't in local repository"
 msgstr ""
 "hiển thị các tham chiếu (refs) từ đầu vào tiêu chuẩn (stdin) cái mà không ở "
@@ -8161,20 +8207,28 @@ msgstr ""
 msgid "git symbolic-ref [options] name [ref]"
 msgstr "git symbolic-ref  [các-tùy-chọn] tên [t.chiếu]"
 
-#: builtin/symbolic-ref.c:38
+#: builtin/symbolic-ref.c:8
+msgid "git symbolic-ref -d [-q] name"
+msgstr "git symbolic-ref -d [-q] tên"
+
+#: builtin/symbolic-ref.c:40
 msgid "suppress error message for non-symbolic (detached) refs"
 msgstr ""
-"chặn các thông tin lỗi cho các tham chiếu (refs) `non-symbolic' (bị tách ra)"
+"chặn các thông tin lỗi cho các tham chiếu (refs) “non-symbolic” (bị tách ra)"
 
-#: builtin/symbolic-ref.c:39
+#: builtin/symbolic-ref.c:41
+msgid "delete symbolic ref"
+msgstr "xóa tham chiếu (ref) tượng trưng"
+
+#: builtin/symbolic-ref.c:42
 msgid "shorten ref output"
 msgstr "làm ngắn kết xuất ref (tham chiếu)"
 
-#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
 msgid "reason"
 msgstr "lý do"
 
-#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18
+#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
 msgid "reason of the update"
 msgstr "lý do cập nhật"
 
@@ -8203,7 +8257,7 @@ msgstr "git tag -v <tên-thẻ>..."
 #: builtin/tag.c:60
 #, c-format
 msgid "malformed object at '%s'"
-msgstr "đối tượng dị hình tại `%s'"
+msgstr "đối tượng dị hình tại “%s”"
 
 #: builtin/tag.c:207
 #, c-format
@@ -8213,17 +8267,17 @@ msgstr "tên thẻ quá dài: %.*s..."
 #: builtin/tag.c:212
 #, c-format
 msgid "tag '%s' not found."
-msgstr "không tìm thấy tìm thấy thẻ `%s'."
+msgstr "không tìm thấy tìm thấy thẻ “%s”."
 
 #: builtin/tag.c:227
 #, c-format
 msgid "Deleted tag '%s' (was %s)\n"
-msgstr "Thẻ đã bị xóa `%s' (trước là %s)\n"
+msgstr "Thẻ đã bị xóa “%s” (trước là %s)\n"
 
 #: builtin/tag.c:239
 #, c-format
 msgid "could not verify the tag '%s'"
-msgstr "không thể thẩm tra thẻ `%s'"
+msgstr "không thể thẩm tra thẻ “%s”"
 
 #: builtin/tag.c:249
 msgid ""
@@ -8236,7 +8290,7 @@ msgstr ""
 "\n"
 "#\n"
 "# Viết các ghi chú cho (thẻ) tag\n"
-"# Những dòng được bắt đầu bằng '#' sẽ được bỏ qua.\n"
+"# Những dòng được bắt đầu bằng “#” sẽ được bỏ qua.\n"
 "#\n"
 
 #: builtin/tag.c:256
@@ -8251,7 +8305,7 @@ msgstr ""
 "\n"
 "#\n"
 "# Viết các ghi chú cho (thẻ) tag\n"
-"# Những dòng được bắt đầu bằng '#' sẽ được bỏ qua; bạn có thể xóa chúng đi "
+"# Những dòng được bắt đầu bằng “#” sẽ được bỏ qua; bạn có thể xóa chúng đi "
 "nếu muốn.\n"
 "#\n"
 
@@ -8282,12 +8336,12 @@ msgstr "Nội dung ghi chú còn lại %s\n"
 
 #: builtin/tag.c:425
 msgid "switch 'points-at' requires an object"
-msgstr "chuyển đến 'points-at' yêu cần một đối tượng"
+msgstr "chuyển đến “points-at” yêu cần một đối tượng"
 
 #: builtin/tag.c:427
 #, c-format
 msgid "malformed object name '%s'"
-msgstr "tên đối tượng dị hình `%s'"
+msgstr "tên đối tượng dị hình “%s”"
 
 #: builtin/tag.c:447
 msgid "list tag names"
@@ -8372,12 +8426,12 @@ msgstr "quá nhiều đối số"
 #: builtin/tag.c:561
 #, c-format
 msgid "'%s' is not a valid tag name."
-msgstr "`%s' không phải thẻ hợp lệ."
+msgstr "“%s” không phải thẻ hợp lệ."
 
 #: builtin/tag.c:566
 #, c-format
 msgid "tag '%s' already exists"
-msgstr "Thẻ `%s' đã tồn tại rồi"
+msgstr "Thẻ “%s” đã tồn tại rồi"
 
 #: builtin/tag.c:584
 #, c-format
@@ -8392,121 +8446,121 @@ msgstr "%s: không thể cập nhật ref (tham chiếu)"
 #: builtin/tag.c:588
 #, c-format
 msgid "Updated tag '%s' (was %s)\n"
-msgstr "Thẻ đã cập nhật `%s' (cũ là %s)\n"
+msgstr "Đã cập nhật thẻ “%s” (trước là %s)\n"
 
 #: builtin/update-index.c:401
 msgid "git update-index [options] [--] [<file>...]"
 msgstr "git update-index [các-tùy-chọn] [<tập-tin>...]"
 
-#: builtin/update-index.c:717
+#: builtin/update-index.c:718
 msgid "continue refresh even when index needs update"
 msgstr "tiếp tục làm mới ngay cả khi bảng mục lục cần được cập nhật"
 
-#: builtin/update-index.c:720
+#: builtin/update-index.c:721
 msgid "refresh: ignore submodules"
 msgstr "refresh: lờ đi mô-đun-con"
 
-#: builtin/update-index.c:723
+#: builtin/update-index.c:724
 msgid "do not ignore new files"
 msgstr "không bỏ qua các tập tin mới tạo"
 
-#: builtin/update-index.c:725
+#: builtin/update-index.c:726
 msgid "let files replace directories and vice-versa"
-msgstr "để các tập tin thay thế các thư mục và `vice-versa'"
+msgstr "để các tập tin thay thế các thư mục và “vice-versa”"
 
-#: builtin/update-index.c:727
+#: builtin/update-index.c:728
 msgid "notice files missing from worktree"
 msgstr "thông báo các tập-tin thiếu trong thư-mục làm việc"
 
-#: builtin/update-index.c:729
+#: builtin/update-index.c:730
 msgid "refresh even if index contains unmerged entries"
 msgstr ""
 "làm tươi mới thậm chí khi bảng mục lục chứa các mục tin chưa được hòa trộn"
 
-#: builtin/update-index.c:732
+#: builtin/update-index.c:733
 msgid "refresh stat information"
 msgstr "lấy lại thông tin thống kê"
 
-#: builtin/update-index.c:736
+#: builtin/update-index.c:737
 msgid "like --refresh, but ignore assume-unchanged setting"
-msgstr "giống --refresh, nhưng bỏ qua các cài đặt `assume-unchanged'"
+msgstr "giống --refresh, nhưng bỏ qua các cài đặt “assume-unchanged”"
 
-#: builtin/update-index.c:740
+#: builtin/update-index.c:741
 msgid "<mode> <object> <path>"
 msgstr "<mode> <đối tượng> <đường dẫn>"
 
-#: builtin/update-index.c:741
+#: builtin/update-index.c:742
 msgid "add the specified entry to the index"
 msgstr "thêm các tập tin đã chỉ ra vào bảng mục lục"
 
-#: builtin/update-index.c:745
+#: builtin/update-index.c:746
 msgid "(+/-)x"
 msgstr "(+/-)x"
 
-#: builtin/update-index.c:746
+#: builtin/update-index.c:747
 msgid "override the executable bit of the listed files"
 msgstr "ghi đè lên bít thi hành của các tập tin được liệt kê"
 
-#: builtin/update-index.c:750
+#: builtin/update-index.c:751
 msgid "mark files as \"not changing\""
 msgstr "Đánh dấu các tập tin là \"không thay đổi\""
 
-#: builtin/update-index.c:753
+#: builtin/update-index.c:754
 msgid "clear assumed-unchanged bit"
 msgstr "xóa bít  assumed-unchanged"
 
-#: builtin/update-index.c:756
+#: builtin/update-index.c:757
 msgid "mark files as \"index-only\""
-msgstr "đánh dấu các tập tin là `chỉ-đọc'"
+msgstr "đánh dấu các tập tin là “chỉ-đọc”"
 
-#: builtin/update-index.c:759
+#: builtin/update-index.c:760
 msgid "clear skip-worktree bit"
 msgstr "xóa bít skip-worktree"
 
-#: builtin/update-index.c:762
+#: builtin/update-index.c:763
 msgid "add to index only; do not add content to object database"
 msgstr ""
 "chỉ thêm vào bảng mục lục; không thêm nội dung vào cơ sở dữ liệu đối tượng"
 
-#: builtin/update-index.c:764
+#: builtin/update-index.c:765
 msgid "remove named paths even if present in worktree"
 msgstr ""
 "gỡ bỏ các đường dẫn được đặt tên thậm chí cả khi nó hiện diện trong thư mục "
 "làm việc"
 
-#: builtin/update-index.c:766
+#: builtin/update-index.c:767
 msgid "with --stdin: input lines are terminated by null bytes"
 msgstr "với tùy chọn --stdin: các dòng đầu vào được chấm dứt bởi ký tự null"
 
-#: builtin/update-index.c:768
+#: builtin/update-index.c:769
 msgid "read list of paths to be updated from standard input"
 msgstr "đọc danh sách đường dẫn cần cập nhật từ đầu vào tiêu chuẩn"
 
-#: builtin/update-index.c:772
+#: builtin/update-index.c:773
 msgid "add entries from standard input to the index"
 msgstr "không thể đọc các mục từ đầu vào tiêu chuẩn vào bảng mục lục"
 
-#: builtin/update-index.c:776
+#: builtin/update-index.c:777
 msgid "repopulate stages #2 and #3 for the listed paths"
 msgstr "phục hồi các trạng thái #2 và #3 cho các đường dẫn được liệt kê"
 
-#: builtin/update-index.c:780
+#: builtin/update-index.c:781
 msgid "only update entries that differ from HEAD"
 msgstr "chỉ cập nhật các mục tin mà nó khác biệt so với HEAD"
 
-#: builtin/update-index.c:784
+#: builtin/update-index.c:785
 msgid "ignore files missing from worktree"
 msgstr "bỏ qua các tập-tin thiếu trong thư-mục làm việc"
 
-#: builtin/update-index.c:787
+#: builtin/update-index.c:788
 msgid "report actions to standard output"
 msgstr "báo cáo các thao tác ra thiết bị xuất chuẩn"
 
-#: builtin/update-index.c:789
+#: builtin/update-index.c:790
 msgid "(for porcelains) forget saved unresolved conflicts"
-msgstr "(cho `porcelains') quên các xung đột chưa được giải quyết đã ghi"
+msgstr "(cho “porcelains”) quên các xung đột chưa được giải quyết đã ghi"
 
-#: builtin/update-index.c:793
+#: builtin/update-index.c:794
 msgid "write index in this format"
 msgstr "ghi mục lục ở định dạng này"
 
@@ -8573,7 +8627,7 @@ msgstr "chỉ hữu ích khi cần gỡ lỗi"
 #: git.c:16
 msgid "See 'git help <command>' for more information on a specific command."
 msgstr ""
-"Chạy lệnh `git help <tên-lệnh>' để có thêm thông tin về lệnh được chỉ ra."
+"Chạy lệnh “git help <tên-lệnh>” để có thêm thông tin về lệnh được chỉ ra."
 
 #: parse-options.h:156
 msgid "no-op (backward compatibility)"
@@ -8605,7 +8659,7 @@ msgstr "Liệt kê, tạo hay là xóa các nhánh"
 
 #: common-cmds.h:11
 msgid "Checkout a branch or paths to the working tree"
-msgstr "Checkout một nhánh hay các đường dẫn tới cây làm việc"
+msgstr "Lấy ra (checkout) một nhánh hay các đường dẫn tới cây làm việc"
 
 #: common-cmds.h:12
 msgid "Clone a repository into a new directory"
@@ -8636,7 +8690,7 @@ msgstr ""
 
 #: common-cmds.h:18
 msgid "Show commit logs"
-msgstr "hiển thị nhật ký các lần commit (chuyển giao)"
+msgstr "Hiển thị nhật ký các lần chuyển giao (commit)"
 
 #: common-cmds.h:19
 msgid "Join two or more development histories together"
@@ -8650,7 +8704,7 @@ msgstr "Di chuyển, đổi tên một tập tin, thư mục hay liên kết tư
 
 #: common-cmds.h:21
 msgid "Fetch from and merge with another repository or a local branch"
-msgstr "Fetch (lấy về) và hòa trộng với kho khác hay nhánh nội bộ"
+msgstr "Lấy về (fetch) và hòa trộn với kho khác hay nhánh nội bộ"
 
 #: common-cmds.h:22
 msgid "Update remote refs along with associated objects"
@@ -8693,7 +8747,7 @@ msgid ""
 "You seem to have moved HEAD since the last 'am' failure.\n"
 "Not rewinding to ORIG_HEAD"
 msgstr ""
-"Bạn có lẽ đã có HEAD đã bị di chuyển đi kể từ lần 'am' thất bại cuối cùng.\n"
+"Bạn có lẽ đã có HEAD đã bị di chuyển đi kể từ lần “am” thất bại cuối cùng.\n"
 "Không thể chuyển tới ORIG_HEAD"
 
 #: git-am.sh:105
@@ -8711,11 +8765,11 @@ msgstr ""
 
 #: git-am.sh:121
 msgid "Cannot fall back to three-way merge."
-msgstr "Đang trở lại để hòa trộn kiểu 'three-way'."
+msgstr "Đang trở lại để hòa trộn kiểu “three-way”."
 
 #: git-am.sh:137
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
-msgstr "Kho thiếu đối tượng blob cần thiết để trở về trên '3-way merge'."
+msgstr "Kho thiếu đối tượng blob cần thiết để trở về trên “3-way merge”."
 
 #: git-am.sh:139
 msgid "Using index info to reconstruct a base tree..."
@@ -8732,7 +8786,7 @@ msgstr ""
 
 #: git-am.sh:163
 msgid "Falling back to patching base and 3-way merge..."
-msgstr "Đang trở lại để vá cơ sở và '3-way merge'..."
+msgstr "Đang trở lại để vá cơ sở và “3-way merge”..."
 
 #: git-am.sh:179
 msgid "Failed to merge in the changes."
@@ -8824,7 +8878,7 @@ msgid ""
 "If there is nothing left to stage, chances are that something else\n"
 "already introduced the same changes; you might want to skip this patch."
 msgstr ""
-"Không có thay đổi nào - bạn đã quên sử dụng lệnh `git add' à?\n"
+"Không có thay đổi nào - bạn đã quên sử dụng lệnh “git add” à?\n"
 "Nếu ở đây không có gì còn lại stage, tình cờ là có một số thứ khác\n"
 "đã sẵn được đưa vào với cùng nội dung thay đổi; bạn có lẽ muốn bỏ qua miếng "
 "vá này."
@@ -8835,7 +8889,7 @@ msgid ""
 "did you forget to use 'git add'?"
 msgstr ""
 "Bạn vẫn có những đường dẫn chưa được hòa trộn trong bảng mục lục của mình\n"
-"bạn đã quên sử dụng lệnh `git add' à?"
+"bạn đã quên sử dụng lệnh “git add” à?"
 
 #: git-am.sh:845
 msgid "No changes -- Patch already applied."
@@ -8873,12 +8927,12 @@ msgstr "Bạn có muốn tôi thực hiện điều này cho bạn không [Y/n]?
 #: git-bisect.sh:95
 #, sh-format
 msgid "unrecognised option: '$arg'"
-msgstr "không công nhận tùy chọn: '$arg'"
+msgstr "không công nhận tùy chọn: “$arg”"
 
 #: git-bisect.sh:99
 #, sh-format
 msgid "'$arg' does not appear to be a valid revision"
-msgstr "'$arg' không có vẻ như là một sự xét lại hợp lệ"
+msgstr "”$arg” không có vẻ như là một sự xét lại hợp lệ"
 
 #: git-bisect.sh:117
 msgid "Bad HEAD - I need a HEAD"
@@ -8889,8 +8943,8 @@ msgstr "HEAD sai - Tôi cần một HEAD"
 msgid ""
 "Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
 msgstr ""
-"Việc checkout '$start_head' gặp lỗi. Hãy thử `git bisect reset "
-"<nhánh_hợp_lệ>'."
+"Việc checkout “$start_head” gặp lỗi. Hãy thử “git bisect reset "
+"<nhánh_hợp_lệ>."
 
 #: git-bisect.sh:140
 msgid "won't bisect on seeked tree"
@@ -8912,7 +8966,7 @@ msgstr "Đầu vào rev sai: $arg"
 
 #: git-bisect.sh:232
 msgid "Please call 'bisect_state' with at least one argument."
-msgstr "Hãy gọi lệnhl 'bisect_state' với ít nhất một đối số."
+msgstr "Hãy gọi lệnhl “bisect_state” với ít nhất một đối số."
 
 #: git-bisect.sh:244
 #, sh-format
@@ -8921,7 +8975,7 @@ msgstr "Đầu vào rev sai: $rev"
 
 #: git-bisect.sh:250
 msgid "'git bisect bad' can take only one argument."
-msgstr "`git bisect bad' có thể lấy chỉ một đối số."
+msgstr "“git bisect bad” có thể lấy chỉ một đối số."
 
 #. have bad but not good.  we could bisect although
 #. this is less optimum.
@@ -8963,7 +9017,7 @@ msgstr "Chúng tôi không bisect."
 #: git-bisect.sh:354
 #, sh-format
 msgid "'$invalid' is not a valid commit"
-msgstr "'$invalid' không phải là lần chuyển giao (commit) hợp lệ"
+msgstr "”$invalid” không phải là lần chuyển giao (commit) hợp lệ"
 
 #: git-bisect.sh:363
 #, sh-format
@@ -8971,8 +9025,8 @@ msgid ""
 "Could not check out original HEAD '$branch'.\n"
 "Try 'git bisect reset <commit>'."
 msgstr ""
-"Không thể check-out HEAD nguyên thủy của '$branch'.\n"
-"Hãy thử `git bisect reset <lần-chuyển-giao>'."
+"Không thể check-out HEAD nguyên thủy của “$branch”.\n"
+"Hãy thử “git bisect reset <lần-chuyển-giao>”."
 
 #: git-bisect.sh:390
 msgid "No logfile given"
@@ -8999,7 +9053,7 @@ msgid ""
 "exit code $res from '$command' is < 0 or >= 128"
 msgstr ""
 "chạy bisect gặp lỗi:\n"
-"mã trả về $res từ lệnh '$command' là < 0 hoặc >= 128"
+"mã trả về $res từ lệnh “$command” là < 0 hoặc >= 128"
 
 #: git-bisect.sh:453
 msgid "bisect run cannot continue any more"
@@ -9012,7 +9066,7 @@ msgid ""
 "'bisect_state $state' exited with error code $res"
 msgstr ""
 "chạy bisect gặp lỗi:\n"
-"'bisect_state $state' đã thoát ra với mã lỗi $res"
+"”bisect_state $state” đã thoát ra với mã lỗi $res"
 
 #: git-bisect.sh:466
 msgid "bisect run success"
@@ -9025,9 +9079,9 @@ msgid ""
 "as appropriate to mark resolution, or use 'git commit -a'."
 msgstr ""
 "Pull là không thể được bởi vì bạn có những tập tin chưa được hòa trộn.\n"
-"Xin hãy sửa chữa chúng trước, và sau đó sử dụng lệnh `git add/rm <tập-tin>'\n"
-"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sử dụng `git "
-"commit -a'."
+"Xin hãy sửa chữa chúng trước, và sau đó sử dụng lệnh “git add/rm <tập-tin>”\n"
+"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sử dụng git "
+"commit -a."
 
 #: git-pull.sh:25
 msgid "Pull is not possible because you have unmerged files."
@@ -9044,7 +9098,7 @@ msgstr ""
 #. The working tree and the index file is still based on the
 #. $orig_head commit, but we are merging into $curr_head.
 #. First update the working tree to match $curr_head.
-#: git-pull.sh:228
+#: git-pull.sh:229
 #, sh-format
 msgid ""
 "Warning: fetch updated the current branch head.\n"
@@ -9055,11 +9109,11 @@ msgstr ""
 "Cảnh báo: đang fast-forward cây làm việc của bạn từ\n"
 "Cảnh báo: commit $orig_head."
 
-#: git-pull.sh:253
+#: git-pull.sh:254
 msgid "Cannot merge multiple branches into empty head"
 msgstr "Không thể hòa trộn nhiều nhánh và trong một head trống rỗng"
 
-#: git-pull.sh:257
+#: git-pull.sh:258
 msgid "Cannot rebase onto multiple branches"
 msgstr "Không thể thực hiện lệnh rebase (cơ cấu lại) trên nhiều nhánh"
 
@@ -9078,7 +9132,7 @@ msgstr ""
 
 #: git-rebase.sh:160
 msgid "The pre-rebase hook refused to rebase."
-msgstr "hook (chương trình móc vào git) pre-rebase từ chối rebase."
+msgstr "Móc (hook) pre-rebase từ chối rebase."
 
 #: git-rebase.sh:165
 msgid "It looks like git-am is in progress. Cannot rebase."
@@ -9097,7 +9151,7 @@ msgstr "Không có tiến trình rebase nào phải không?"
 #: git-rebase.sh:312
 msgid "The --edit-todo action can only be used during interactive rebase."
 msgstr ""
-"Hành động `--edit-todo' chỉ có thể dùng trong quá trình `rebase' (sửa lịch "
+"Hành động “--edit-todo” chỉ có thể dùng trong quá trình “rebase” (sửa lịch "
 "sử) tương tác."
 
 #: git-rebase.sh:319
@@ -9148,12 +9202,12 @@ msgstr "thượng nguồn không hợp lệ $upstream_name"
 #: git-rebase.sh:428
 #, sh-format
 msgid "$onto_name: there are more than one merge bases"
-msgstr "$onto_name: ở đây có nhiều hơn một"
+msgstr "$onto_name: ở đây có nhiều hơn một nền móng hòa trộn"
 
 #: git-rebase.sh:431 git-rebase.sh:435
 #, sh-format
 msgid "$onto_name: there is no merge base"
-msgstr "$onto_name: ở đây không có gì để hòa trộn"
+msgstr "$onto_name: ở đây không có nền móng hòa trộn nào"
 
 #: git-rebase.sh:440
 #, sh-format
@@ -9167,7 +9221,7 @@ msgstr "nghiêm trọng: không có nhánh như thế: $branch_name"
 
 #: git-rebase.sh:483
 msgid "Please commit or stash them."
-msgstr "Xin hãy commit hoặc stash chúng."
+msgstr "Xin hãy commit hoặc tạm cất (stash) chúng."
 
 #: git-rebase.sh:501
 #, sh-format
@@ -9240,8 +9294,8 @@ msgid ""
 "error: unknown option for 'stash save': $option\n"
 "       To provide a message, use git stash save -- '$option'"
 msgstr ""
-"lỗi: không hiểu tùy chọn cho 'stash save': $option\n"
-"       Để cung cấp một thông điệp, sử dụng git stash save -- '$option'"
+"lỗi: không hiểu tùy chọn cho “stash save”: $option\n"
+"       Để cung cấp một thông điệp, sử dụng git stash save -- “$option”"
 
 #: git-stash.sh:223
 msgid "No local changes to save"
@@ -9276,12 +9330,12 @@ msgstr "$reference không phải là tham chiếu hợp lệ"
 #: git-stash.sh:393
 #, sh-format
 msgid "'$args' is not a stash-like commit"
-msgstr "'$args' không phải là lần chuyển giao (commit) giống-stash"
+msgstr "”$args” không phải là lần chuyển giao (commit) giống-stash"
 
 #: git-stash.sh:404
 #, sh-format
 msgid "'$args' is not a stash reference"
-msgstr "'$args' không phải tham chiếu đến stash"
+msgstr "”$args” không phải tham chiếu đến stash"
 
 #: git-stash.sh:412
 msgid "unable to refresh index"
@@ -9325,41 +9379,41 @@ msgstr "Chưa chỉ ra tên của nhánh"
 msgid "(To restore them type \"git stash apply\")"
 msgstr "(Để phục hồi lại chúng hãy gõ \"git stash apply\")"
 
-#: git-submodule.sh:88
+#: git-submodule.sh:89
 #, sh-format
 msgid "cannot strip one component off url '$remoteurl'"
-msgstr "không thể tháo bỏ một thành phần ra khỏi url '$remoteurl'"
+msgstr "không thể tháo bỏ một thành phần ra khỏi “$remoteurl” url"
 
-#: git-submodule.sh:167
+#: git-submodule.sh:168
 #, sh-format
 msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
 msgstr ""
 "Không tìm thấy ánh xạ (mapping) mô-đun-con trong .gitmodules cho đường dẫn "
-"'$sm_path'"
+"“$sm_path”"
 
 #: git-submodule.sh:211
 #, sh-format
 msgid "Clone of '$url' into submodule path '$sm_path' failed"
-msgstr "Nhân bản '$url' vào đường dẫn mô-đun-con '$sm_path' gặp lỗi"
+msgstr "Nhân bản “$url” vào đường dẫn mô-đun-con “$sm_path” gặp lỗi"
 
 #: git-submodule.sh:223
 #, sh-format
 msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
 msgstr ""
-"Gitdir '$a' là bộ phận của đường dẫn mô-đun-con '$b' hoặc \"vice versa\""
+"Gitdir “$a” là bộ phận của đường dẫn mô-đun-con “$b” hoặc \"vice versa\""
 
-#: git-submodule.sh:312
+#: git-submodule.sh:316
 #, sh-format
 msgid "repo URL: '$repo' must be absolute or begin with ./|../"
 msgstr ""
-"repo URL: '$repo' phải là đường dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
+"repo URL: “$repo” phải là đường dẫn tuyệt đối hoặc là bắt đầu bằng ./|../"
 
-#: git-submodule.sh:329
+#: git-submodule.sh:333
 #, sh-format
 msgid "'$sm_path' already exists in the index"
-msgstr "'$sm_path' thực sự đã tồn tại ở bảng mục lục rồi"
+msgstr "”$sm_path” thực sự đã tồn tại ở bảng mục lục rồi"
 
-#: git-submodule.sh:333
+#: git-submodule.sh:337
 #, sh-format
 msgid ""
 "The following path is ignored by one of your .gitignore files:\n"
@@ -9371,162 +9425,199 @@ msgstr ""
 "$sm_path\n"
 "Sử dụng -f nếu bạn thực sự muốn thêm nó vào."
 
-#: git-submodule.sh:344
+#: git-submodule.sh:355
 #, sh-format
 msgid "Adding existing repo at '$sm_path' to the index"
-msgstr "Đang thêm repo có sẵn tại '$sm_path' vào bảng mục lục"
+msgstr "Đang thêm repo có sẵn tại “$sm_path” vào bảng mục lục"
 
-#: git-submodule.sh:346
+#: git-submodule.sh:357
 #, sh-format
 msgid "'$sm_path' already exists and is not a valid git repo"
-msgstr "'$sm_path' đã tồn tại từ trước và không phải là một kho git hợp lệ"
+msgstr "”$sm_path” đã tồn tại từ trước và không phải là một kho git hợp lệ"
+
+#: git-submodule.sh:365
+#, sh-format
+msgid "A git directory for '$sm_name' is found locally with remote(s):"
+msgstr ""
+"Thư mục git cho '$sm_name' được tìm thấy một cách cục bộ với các máy chủ:"
 
-#: git-submodule.sh:360
+#: git-submodule.sh:367
+#, sh-format
+msgid ""
+"If you want to reuse this local git directory instead of cloning again from"
+msgstr "Nếu bạn muốn dùng lại thư mục git nội bộ này thay vì nhân bản từ nó"
+
+#: git-submodule.sh:369
+#, sh-format
+msgid ""
+"use the '--force' option. If the local git directory is not the correct repo"
+msgstr ""
+"dùng tùy chọn '--force'. Nếu thư mục git nội bộ không phải là repo (kho) đúng"
+
+#: git-submodule.sh:370
+#, sh-format
+msgid ""
+"or you are unsure what this means choose another name with the '--name' "
+"option."
+msgstr ""
+"hay bạn không chắc chắn điều đó có nghĩa gì chọn tên khác với tùy chọn '--"
+"name'."
+
+#: git-submodule.sh:372
+#, sh-format
+msgid "Reactivating local git directory for submodule '$sm_name'."
+msgstr ""
+"Phục hồi sự hoạt động của thư mục git nội bộ cho mô-đun-con '$sm_name'."
+
+#: git-submodule.sh:384
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
-msgstr "Không thể checkout mô-đun con '$sm_path'"
+msgstr "Không thể checkout mô-đun con “$sm_path”"
 
-#: git-submodule.sh:365
+#: git-submodule.sh:389
 #, sh-format
 msgid "Failed to add submodule '$sm_path'"
-msgstr "Gặp lỗi khi thêm mô-đun con '$sm_path'"
+msgstr "Gặp lỗi khi thêm mô-đun con “$sm_path”"
 
-#: git-submodule.sh:370
+#: git-submodule.sh:394
 #, sh-format
 msgid "Failed to register submodule '$sm_path'"
-msgstr "Gặp lỗi khi đăng ký với hệ thống mô-đun con '$sm_path'"
+msgstr "Gặp lỗi khi đăng ký với hệ thống mô-đun con “$sm_path”"
 
-#: git-submodule.sh:413
+#: git-submodule.sh:437
 #, sh-format
 msgid "Entering '$prefix$sm_path'"
-msgstr "Đang nhập '$prefix$sm_path'"
+msgstr "Đang nhập “$prefix$sm_path”"
 
-#: git-submodule.sh:427
+#: git-submodule.sh:451
 #, sh-format
 msgid "Stopping at '$sm_path'; script returned non-zero status."
-msgstr "Dừng lại tại '$sm_path'; script trả về trạng thái khác không."
+msgstr "Dừng lại tại “$sm_path”; script trả về trạng thái khác không."
 
-#: git-submodule.sh:471
+#: git-submodule.sh:495
 #, sh-format
 msgid "No url found for submodule path '$sm_path' in .gitmodules"
 msgstr ""
-"Không tìm thấy url cho đường dẫn mô-đun-con '$sm_path' trong .gitmodules"
+"Không tìm thấy url cho đường dẫn mô-đun-con “$sm_path” trong .gitmodules"
 
-#: git-submodule.sh:480
+#: git-submodule.sh:504
 #, sh-format
 msgid "Failed to register url for submodule path '$sm_path'"
-msgstr "Gặp lỗi khi đăng ký url cho đường dẫn mô-đun-con '$sm_path'"
+msgstr "Gặp lỗi khi đăng ký url cho đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:482
+#: git-submodule.sh:506
 #, sh-format
 msgid "Submodule '$name' ($url) registered for path '$sm_path'"
-msgstr "Mô-đun-con '$name' ($url) được đăng ký cho đường dẫn '$sm_path'"
+msgstr "Mô-đun-con “$name” ($url) được đăng ký cho đường dẫn “$sm_path”"
 
-#: git-submodule.sh:490
+#: git-submodule.sh:514
 #, sh-format
 msgid "Failed to register update mode for submodule path '$sm_path'"
 msgstr ""
-"Gặp lỗi khi đăng ký chế độ cập nhật cho đường dẫn mô-đun-con '$sm_path'"
+"Gặp lỗi khi đăng ký chế độ cập nhật cho đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:590
+#: git-submodule.sh:614
 #, sh-format
 msgid ""
 "Submodule path '$sm_path' not initialized\n"
 "Maybe you want to use 'update --init'?"
 msgstr ""
-"Đường dẫn mô-đun-con '$sm_path' chưa được khởi tạo\n"
-"Có lẽ bạn muốn sử dụng lệnh 'update --init'?"
+"Đường dẫn mô-đun-con “$sm_path” chưa được khởi tạo\n"
+"Có lẽ bạn muốn sử dụng lệnh “update --init”?"
 
-#: git-submodule.sh:603
+#: git-submodule.sh:627
 #, sh-format
 msgid "Unable to find current revision in submodule path '$sm_path'"
 msgstr ""
-"Không tìm thấy điểm xét lại hiện hành trong đường dẫn mô-đun-con '$sm_path'"
+"Không tìm thấy điểm xét lại hiện hành trong đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:622
+#: git-submodule.sh:646
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
-msgstr "Không thể lấy về (fetch) trong đường dẫn mô-đun-con '$sm_path'"
+msgstr "Không thể lấy về (fetch) trong đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:636
+#: git-submodule.sh:660
 #, sh-format
 msgid "Unable to rebase '$sha1' in submodule path '$sm_path'"
-msgstr "Không thể rebase '$sha1' trong đường dẫn mô-đun-con '$sm_path'"
+msgstr "Không thể rebase “$sha1” trong đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:637
+#: git-submodule.sh:661
 #, sh-format
 msgid "Submodule path '$sm_path': rebased into '$sha1'"
-msgstr "Đường dẫn mô-đun-con '$sm_path': được rebase vào trong '$sha1'"
+msgstr "Đường dẫn mô-đun-con “$sm_path”: được rebase vào trong “$sha1”"
 
-#: git-submodule.sh:642
+#: git-submodule.sh:666
 #, sh-format
 msgid "Unable to merge '$sha1' in submodule path '$sm_path'"
 msgstr ""
-"Không thể hòa trộn (merge) '$sha1' trong đường dẫn mô-đun-con '$sm_path'"
+"Không thể hòa trộn (merge) “$sha1” trong đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:643
+#: git-submodule.sh:667
 #, sh-format
 msgid "Submodule path '$sm_path': merged in '$sha1'"
-msgstr "Đường dẫn mô-đun-con '$sm_path': được hòa trộn vào '$sha1'"
+msgstr "Đường dẫn mô-đun-con “$sm_path”: được hòa trộn vào “$sha1”"
 
-#: git-submodule.sh:648
+#: git-submodule.sh:672
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$sm_path'"
-msgstr "Không thể checkout '$sha1' trong đường dẫn mô-đun-con '$sm_path'"
+msgstr "Không thể checkout “$sha1” trong đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:649
+#: git-submodule.sh:673
 #, sh-format
 msgid "Submodule path '$sm_path': checked out '$sha1'"
-msgstr "Đường dẫn mô-đun-con '$sm_path': được checkout '$sha1'"
+msgstr "Đường dẫn mô-đun-con “$sm_path”: được checkout “$sha1”"
 
-#: git-submodule.sh:671 git-submodule.sh:995
+#: git-submodule.sh:695 git-submodule.sh:1017
 #, sh-format
 msgid "Failed to recurse into submodule path '$sm_path'"
-msgstr "Gặp lỗi khi đệ quy vào trong đường dẫn mô-đun-con '$sm_path'"
+msgstr "Gặp lỗi khi đệ quy vào trong đường dẫn mô-đun-con “$sm_path”"
 
-#: git-submodule.sh:779
+#: git-submodule.sh:803
 msgid "The --cached option cannot be used with the --files option"
 msgstr "Tùy chọn --cached không thể dùng cùng với tùy chọn --files"
 
 #. unexpected type
-#: git-submodule.sh:819
+#: git-submodule.sh:843
 #, sh-format
 msgid "unexpected mode $mod_dst"
 msgstr "chế độ không như mong chờ $mod_dst"
 
-#: git-submodule.sh:837
+#: git-submodule.sh:861
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_src"
 msgstr "  Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_src"
 
-#: git-submodule.sh:840
+#: git-submodule.sh:864
 #, sh-format
 msgid "  Warn: $name doesn't contain commit $sha1_dst"
 msgstr "  Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_dst"
 
-#: git-submodule.sh:843
+#: git-submodule.sh:867
 #, sh-format
 msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
 msgstr ""
 "  Cảnh báo: $name không chứa những lần chuyển giao (commit) $sha1_src và "
 "$sha1_dst"
 
-#: git-submodule.sh:868
+#: git-submodule.sh:892
 msgid "blob"
 msgstr "blob"
 
-#: git-submodule.sh:906
+#: git-submodule.sh:930
 msgid "# Submodules changed but not updated:"
-msgstr "# Những mô-đun-con đã bị thay đổi nhưng chưa được cập nhật:"
+msgstr "# Các mô-đun-con đã bị thay đổi nhưng chưa được cập nhật:"
 
-#: git-submodule.sh:908
+#: git-submodule.sh:932
 msgid "# Submodule changes to be committed:"
 msgstr "# Những thay đổi mô-đun-con được chuyển giao (commit):"
 
-#: git-submodule.sh:1054
+#: git-submodule.sh:1080
 #, sh-format
-msgid "Synchronizing submodule url for '$name'"
-msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'"
+msgid "Synchronizing submodule url for '$prefix$sm_path'"
+msgstr "Url Mô-đun-con đồng bộ hóa cho '$prefix$sm_path'"
+
+#~ msgid "git remote set-head <name> (-a | -d | <branch>])"
+#~ msgstr "git remote set-head <tên> (-a | -d | <nhánh>])"
 
 #~ msgid " 0 files changed"
 #~ msgstr " 0 có tập tin nào thay đổi cả"
@@ -9595,7 +9686,7 @@ msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'"
 #~ msgstr "%s: đã được xóa/thay-tên"
 
 #~ msgid "'%s': not a documentation directory."
-#~ msgstr "'%s': không phải là một thư mục tài liệu."
+#~ msgstr "”%s”: không phải là một thư mục tài liệu."
 
 #~ msgid "--"
 #~ msgstr "--"
@@ -9604,10 +9695,5 @@ msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'"
 #~ msgstr ""
 #~ "Không thể rút trích địa chỉ thư điện tử từ định danh người chuyển giao"
 
-#, fuzzy
 #~ msgid "could not parse commit %s\n"
-#~ msgstr "Không thể phân tích commit (lần chuyển giao) %s\n"
-
-#, fuzzy
-#~ msgid "cherry-pick"
-#~ msgstr "< Chọn D-Mod"
+#~ msgstr "không thể phân tích commit (lần chuyển giao) %s\n"
index 8b1ea9f..91bb2d3 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -231,7 +231,7 @@ static int is_rfc822_special(char ch)
        }
 }
 
-static int has_rfc822_specials(const char *s, int len)
+static int needs_rfc822_quoting(const char *s, int len)
 {
        int i;
        for (i = 0; i < len; i++)
@@ -240,6 +240,17 @@ static int has_rfc822_specials(const char *s, int len)
        return 0;
 }
 
+static int last_line_length(struct strbuf *sb)
+{
+       int i;
+
+       /* How many bytes are already used on the last line? */
+       for (i = sb->len - 1; i >= 0; i--)
+               if (sb->buf[i] == '\n')
+                       break;
+       return sb->len - (i + 1);
+}
+
 static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
 {
        int i;
@@ -261,57 +272,110 @@ static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
        strbuf_addch(out, '"');
 }
 
-static int is_rfc2047_special(char ch)
+enum rfc2047_type {
+       RFC2047_SUBJECT,
+       RFC2047_ADDRESS,
+};
+
+static int is_rfc2047_special(char ch, enum rfc2047_type type)
 {
-       return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
+       /*
+        * rfc2047, section 4.2:
+        *
+        *    8-bit values which correspond to printable ASCII characters other
+        *    than "=", "?", and "_" (underscore), MAY be represented as those
+        *    characters.  (But see section 5 for restrictions.)  In
+        *    particular, SPACE and TAB MUST NOT be represented as themselves
+        *    within encoded words.
+        */
+
+       /*
+        * rule out non-ASCII characters and non-printable characters (the
+        * non-ASCII check should be redundant as isprint() is not localized
+        * and only knows about ASCII, but be defensive about that)
+        */
+       if (non_ascii(ch) || !isprint(ch))
+               return 1;
+
+       /*
+        * rule out special printable characters (' ' should be the only
+        * whitespace character considered printable, but be defensive and use
+        * isspace())
+        */
+       if (isspace(ch) || ch == '=' || ch == '?' || ch == '_')
+               return 1;
+
+       /*
+        * rfc2047, section 5.3:
+        *
+        *    As a replacement for a 'word' entity within a 'phrase', for example,
+        *    one that precedes an address in a From, To, or Cc header.  The ABNF
+        *    definition for 'phrase' from RFC 822 thus becomes:
+        *
+        *    phrase = 1*( encoded-word / word )
+        *
+        *    In this case the set of characters that may be used in a "Q"-encoded
+        *    'encoded-word' is restricted to: <upper and lower case ASCII
+        *    letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
+        *    (underscore, ASCII 95.)>.  An 'encoded-word' that appears within a
+        *    'phrase' MUST be separated from any adjacent 'word', 'text' or
+        *    'special' by 'linear-white-space'.
+        */
+
+       if (type != RFC2047_ADDRESS)
+               return 0;
+
+       /* '=' and '_' are special cases and have been checked above */
+       return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/');
 }
 
-static void add_rfc2047(struct strbuf *sb, const char *line, int len,
-                      const char *encoding)
+static int needs_rfc2047_encoding(const char *line, int len,
+                                 enum rfc2047_type type)
 {
-       static const int max_length = 78; /* per rfc2822 */
        int i;
-       int line_len;
-
-       /* How many bytes are already used on the current line? */
-       for (i = sb->len - 1; i >= 0; i--)
-               if (sb->buf[i] == '\n')
-                       break;
-       line_len = sb->len - (i+1);
 
        for (i = 0; i < len; i++) {
                int ch = line[i];
                if (non_ascii(ch) || ch == '\n')
-                       goto needquote;
+                       return 1;
                if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
-                       goto needquote;
+                       return 1;
        }
-       strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
-       return;
 
-needquote:
+       return 0;
+}
+
+static void add_rfc2047(struct strbuf *sb, const char *line, int len,
+                      const char *encoding, enum rfc2047_type type)
+{
+       static const int max_encoded_length = 76; /* per rfc2047 */
+       int i;
+       int line_len = last_line_length(sb);
+
        strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
        strbuf_addf(sb, "=?%s?q?", encoding);
        line_len += strlen(encoding) + 5; /* 5 for =??q? */
        for (i = 0; i < len; i++) {
                unsigned ch = line[i] & 0xFF;
+               int is_special = is_rfc2047_special(ch, type);
+
+               /*
+                * According to RFC 2047, we could encode the special character
+                * ' ' (space) with '_' (underscore) for readability. But many
+                * programs do not understand this and just leave the
+                * underscore in place. Thus, we do nothing special here, which
+                * causes ' ' to be encoded as '=20', avoiding this problem.
+                */
 
-               if (line_len >= max_length - 2) {
+               if (line_len + 2 + (is_special ? 3 : 1) > max_encoded_length) {
                        strbuf_addf(sb, "?=\n =?%s?q?", encoding);
                        line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
                }
 
-               /*
-                * We encode ' ' using '=20' even though rfc2047
-                * allows using '_' for readability.  Unfortunately,
-                * many programs do not understand this and just
-                * leave the underscore in place.
-                */
-               if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
+               if (is_special) {
                        strbuf_addf(sb, "=%02X", ch);
                        line_len += 3;
-               }
-               else {
+               } else {
                        strbuf_addch(sb, ch);
                        line_len++;
                }
@@ -323,6 +387,7 @@ void pp_user_info(const struct pretty_print_context *pp,
                  const char *what, struct strbuf *sb,
                  const char *line, const char *encoding)
 {
+       int max_length = 78; /* per rfc2822 */
        char *date;
        int namelen;
        unsigned long time;
@@ -340,25 +405,27 @@ void pp_user_info(const struct pretty_print_context *pp,
        if (pp->fmt == CMIT_FMT_EMAIL) {
                char *name_tail = strchr(line, '<');
                int display_name_length;
-               int final_line;
                if (!name_tail)
                        return;
                while (line < name_tail && isspace(name_tail[-1]))
                        name_tail--;
                display_name_length = name_tail - line;
                strbuf_addstr(sb, "From: ");
-               if (!has_rfc822_specials(line, display_name_length)) {
-                       add_rfc2047(sb, line, display_name_length, encoding);
-               } else {
+               if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {
+                       add_rfc2047(sb, line, display_name_length,
+                                               encoding, RFC2047_ADDRESS);
+                       max_length = 76; /* per rfc2047 */
+               } else if (needs_rfc822_quoting(line, display_name_length)) {
                        struct strbuf quoted = STRBUF_INIT;
                        add_rfc822_quoted(&quoted, line, display_name_length);
-                       add_rfc2047(sb, quoted.buf, quoted.len, encoding);
+                       strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
+                                                       -6, 1, max_length);
                        strbuf_release(&quoted);
+               } else {
+                       strbuf_add_wrapped_bytes(sb, line, display_name_length,
+                                                       -6, 1, max_length);
                }
-               for (final_line = 0; final_line < sb->len; final_line++)
-                       if (sb->buf[sb->len - final_line - 1] == '\n')
-                               break;
-               if (namelen - display_name_length + final_line > 78) {
+               if (namelen - display_name_length + last_line_length(sb) > max_length) {
                        strbuf_addch(sb, '\n');
                        if (!isspace(name_tail[0]))
                                strbuf_addch(sb, ' ');
@@ -500,11 +567,11 @@ 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;
-       if (!strcmp(use_encoding, output_encoding))
+       if (same_encoding(use_encoding, output_encoding))
                if (encoding) /* we'll strip encoding header later */
                        out = xstrdup(commit->buffer);
                else
@@ -1033,9 +1100,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                }
                return 0;       /* unknown %g placeholder */
        case 'N':
-               if (c->pretty_ctx->show_notes) {
-                       format_display_notes(commit->object.sha1, sb,
-                                   get_log_output_encoding(), 0);
+               if (c->pretty_ctx->notes_message) {
+                       strbuf_addstr(sb, c->pretty_ctx->notes_message);
                        return 1;
                }
                return 0;
@@ -1184,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);
@@ -1278,6 +1336,7 @@ void pp_title_line(const struct pretty_print_context *pp,
                   const char *encoding,
                   int need_8bit_cte)
 {
+       static const int max_length = 78; /* per rfc2047 */
        struct strbuf title;
 
        strbuf_init(&title, 80);
@@ -1287,7 +1346,12 @@ void pp_title_line(const struct pretty_print_context *pp,
        strbuf_grow(sb, title.len + 1024);
        if (pp->subject) {
                strbuf_addstr(sb, pp->subject);
-               add_rfc2047(sb, title.buf, title.len, encoding);
+               if (needs_rfc2047_encoding(title.buf, title.len, RFC2047_SUBJECT))
+                       add_rfc2047(sb, title.buf, title.len,
+                                               encoding, RFC2047_SUBJECT);
+               else
+                       strbuf_add_wrapped_bytes(sb, title.buf, title.len,
+                                        -last_line_length(sb), 1, max_length);
        } else {
                strbuf_addbuf(sb, &title);
        }
@@ -1341,16 +1405,6 @@ void pp_remainder(const struct pretty_print_context *pp,
        }
 }
 
-char *reencode_commit_message(const struct commit *commit, const char **encoding_p)
-{
-       const char *encoding;
-
-       encoding = get_log_output_encoding();
-       if (encoding_p)
-               *encoding_p = encoding;
-       return logmsg_reencode(commit, encoding);
-}
-
 void pretty_print_commit(const struct pretty_print_context *pp,
                         const struct commit *commit,
                         struct strbuf *sb)
@@ -1367,7 +1421,8 @@ void pretty_print_commit(const struct pretty_print_context *pp,
                return;
        }
 
-       reencoded = reencode_commit_message(commit, &encoding);
+       encoding = get_log_output_encoding();
+       reencoded = logmsg_reencode(commit, encoding);
        if (reencoded) {
                msg = reencoded;
        }
@@ -1427,10 +1482,6 @@ void pretty_print_commit(const struct pretty_print_context *pp,
        if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
 
-       if (pp->show_notes)
-               format_display_notes(commit->object.sha1, sb, encoding,
-                                    NOTES_SHOW_HEADER | NOTES_INDENT);
-
        free(reencoded);
 }
 
diff --git a/refs.c b/refs.c
index da74a2b..541fec2 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1202,6 +1202,8 @@ int peel_ref(const char *refname, unsigned char *sha1)
        if (current_ref && (current_ref->name == refname
                || !strcmp(current_ref->name, refname))) {
                if (current_ref->flag & REF_KNOWS_PEELED) {
+                       if (is_null_sha1(current_ref->u.value.peeled))
+                           return -1;
                        hashcpy(sha1, current_ref->u.value.peeled);
                        return 0;
                }
@@ -1223,9 +1225,16 @@ int peel_ref(const char *refname, unsigned char *sha1)
        }
 
 fallback:
-       o = parse_object(base);
-       if (o && o->type == OBJ_TAG) {
-               o = deref_tag(o, refname, 0);
+       o = lookup_unknown_object(base);
+       if (o->type == OBJ_NONE) {
+               int type = sha1_object_info(base, NULL);
+               if (type < 0)
+                       return -1;
+               o->type = type;
+       }
+
+       if (o->type == OBJ_TAG) {
+               o = deref_tag_noverify(o);
                if (o) {
                        hashcpy(sha1, o->sha1);
                        return 0;
@@ -1735,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;
@@ -1744,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);
 }
@@ -1753,32 +1765,24 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
        struct ref_lock *lock;
        int err, i = 0, ret = 0, flag = 0;
 
-       lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
+       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
        if (!lock)
                return 1;
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
                /* loose */
-               const char *path;
-
-               if (!(delopt & REF_NODEREF)) {
-                       i = strlen(lock->lk->filename) - 5; /* .lock */
-                       lock->lk->filename[i] = 0;
-                       path = lock->lk->filename;
-               } else {
-                       path = git_path("%s", refname);
-               }
-               err = unlink_or_warn(path);
+               i = strlen(lock->lk->filename) - 5; /* .lock */
+               lock->lk->filename[i] = 0;
+               err = unlink_or_warn(lock->lk->filename);
                if (err && errno != ENOENT)
                        ret = 1;
 
-               if (!(delopt & REF_NODEREF))
-                       lock->lk->filename[i] = '.';
+               lock->lk->filename[i] = '.';
        }
        /* removing the loose one could have resurrected an earlier
         * packed one.  Also, if it was not loose we need to repack
         * without it.
         */
-       ret |= repack_without_ref(refname);
+       ret |= repack_without_ref(lock->ref_name);
 
        unlink_or_warn(git_path("logs/%s", lock->ref_name));
        invalidate_ref_cache(NULL);
index 42716c5..9a8b123 100644 (file)
@@ -356,7 +356,7 @@ static int run_slot(struct active_request_slot *slot)
        slot->curl_result = curl_easy_perform(slot->curl);
        finish_active_slot(slot);
 
-       err = handle_curl_result(slot, &results);
+       err = handle_curl_result(&results);
        if (err != HTTP_OK && err != HTTP_REAUTH) {
                error("RPC failed; result=%d, HTTP code = %ld",
                      results.curl_result, results.http_code);
@@ -400,6 +400,7 @@ static int post_rpc(struct rpc_state *rpc)
        struct curl_slist *headers = NULL;
        int use_gzip = rpc->gzip_request;
        char *gzip_body = NULL;
+       size_t gzip_size = 0;
        int err, large_request = 0;
 
        /* Try to load the entire request, if we can fit it into the
@@ -431,6 +432,11 @@ static int post_rpc(struct rpc_state *rpc)
                        return -1;
        }
 
+       headers = curl_slist_append(headers, rpc->hdr_content_type);
+       headers = curl_slist_append(headers, rpc->hdr_accept);
+       headers = curl_slist_append(headers, "Expect:");
+
+retry:
        slot = get_active_slot();
 
        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
@@ -438,10 +444,6 @@ static int post_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
        curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
 
-       headers = curl_slist_append(headers, rpc->hdr_content_type);
-       headers = curl_slist_append(headers, rpc->hdr_accept);
-       headers = curl_slist_append(headers, "Expect:");
-
        if (large_request) {
                /* The request body is large and the size cannot be predicted.
                 * We must use chunked encoding to send it.
@@ -459,24 +461,32 @@ static int post_rpc(struct rpc_state *rpc)
                        fflush(stderr);
                }
 
+       } else if (gzip_body) {
+               /*
+                * If we are looping to retry authentication, then the previous
+                * run will have set up the headers and gzip buffer already,
+                * and we just need to send it.
+                */
+               curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
+               curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
+
        } else if (use_gzip && 1024 < rpc->len) {
                /* The client backend isn't giving us compressed data so
                 * we can try to deflate it ourselves, this may save on.
                 * the transfer time.
                 */
-               size_t size;
                git_zstream stream;
                int ret;
 
                memset(&stream, 0, sizeof(stream));
                git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION);
-               size = git_deflate_bound(&stream, rpc->len);
-               gzip_body = xmalloc(size);
+               gzip_size = git_deflate_bound(&stream, rpc->len);
+               gzip_body = xmalloc(gzip_size);
 
                stream.next_in = (unsigned char *)rpc->buf;
                stream.avail_in = rpc->len;
                stream.next_out = (unsigned char *)gzip_body;
-               stream.avail_out = size;
+               stream.avail_out = gzip_size;
 
                ret = git_deflate(&stream, Z_FINISH);
                if (ret != Z_STREAM_END)
@@ -486,16 +496,16 @@ static int post_rpc(struct rpc_state *rpc)
                if (ret != Z_OK)
                        die("cannot deflate request; zlib end error %d", ret);
 
-               size = stream.total_out;
+               gzip_size = stream.total_out;
 
                headers = curl_slist_append(headers, "Content-Encoding: gzip");
                curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);
-               curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, size);
+               curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size);
 
                if (options.verbosity > 1) {
                        fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n",
                                rpc->service_name,
-                               (unsigned long)rpc->len, (unsigned long)size);
+                               (unsigned long)rpc->len, (unsigned long)gzip_size);
                        fflush(stderr);
                }
        } else {
@@ -515,9 +525,9 @@ static int post_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
 
-       do {
-               err = run_slot(slot);
-       } while (err == HTTP_REAUTH && !large_request && !use_gzip);
+       err = run_slot(slot);
+       if (err == HTTP_REAUTH && !large_request)
+               goto retry;
        if (err != HTTP_OK)
                err = -1;
 
diff --git a/remote-testsvn.c b/remote-testsvn.c
new file mode 100644 (file)
index 0000000..5ddf11c
--- /dev/null
@@ -0,0 +1,344 @@
+#include "cache.h"
+#include "remote.h"
+#include "strbuf.h"
+#include "url.h"
+#include "exec_cmd.h"
+#include "run-command.h"
+#include "vcs-svn/svndump.h"
+#include "notes.h"
+#include "argv-array.h"
+
+static const char *url;
+static int dump_from_file;
+static const char *private_ref;
+static const char *remote_ref = "refs/heads/master";
+static const char *marksfilename, *notes_ref;
+struct rev_note { unsigned int rev_nr; };
+
+static int cmd_capabilities(const char *line);
+static int cmd_import(const char *line);
+static int cmd_list(const char *line);
+
+typedef int (*input_command_handler)(const char *);
+struct input_command_entry {
+       const char *name;
+       input_command_handler fn;
+       unsigned char batchable;        /* whether the command starts or is part of a batch */
+};
+
+static const struct input_command_entry input_command_list[] = {
+       { "capabilities", cmd_capabilities, 0 },
+       { "import", cmd_import, 1 },
+       { "list", cmd_list, 0 },
+       { NULL, NULL }
+};
+
+static int cmd_capabilities(const char *line)
+{
+       printf("import\n");
+       printf("bidi-import\n");
+       printf("refspec %s:%s\n\n", remote_ref, private_ref);
+       fflush(stdout);
+       return 0;
+}
+
+static void terminate_batch(void)
+{
+       /* terminate a current batch's fast-import stream */
+       printf("done\n");
+       fflush(stdout);
+}
+
+/* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */
+static char *read_ref_note(const unsigned char sha1[20])
+{
+       const unsigned char *note_sha1;
+       char *msg = NULL;
+       unsigned long msglen;
+       enum object_type type;
+
+       init_notes(NULL, notes_ref, NULL, 0);
+       if (!(note_sha1 = get_note(NULL, sha1)))
+               return NULL;    /* note tree not found */
+       if (!(msg = read_sha1_file(note_sha1, &type, &msglen)))
+               error("Empty notes tree. %s", notes_ref);
+       else if (!msglen || type != OBJ_BLOB) {
+               error("Note contains unusable content. "
+                       "Is something else using this notes tree? %s", notes_ref);
+               free(msg);
+               msg = NULL;
+       }
+       free_notes(NULL);
+       return msg;
+}
+
+static int parse_rev_note(const char *msg, struct rev_note *res)
+{
+       const char *key, *value, *end;
+       size_t len;
+
+       while (*msg) {
+               end = strchr(msg, '\n');
+               len = end ? end - msg : strlen(msg);
+
+               key = "Revision-number: ";
+               if (!prefixcmp(msg, key)) {
+                       long i;
+                       char *end;
+                       value = msg + strlen(key);
+                       i = strtol(value, &end, 0);
+                       if (end == value || i < 0 || i > UINT32_MAX)
+                               return -1;
+                       res->rev_nr = i;
+                       return 0;
+               }
+               msg += len + 1;
+       }
+       /* didn't find it */
+       return -1;
+}
+
+static int note2mark_cb(const unsigned char *object_sha1,
+               const unsigned char *note_sha1, char *note_path,
+               void *cb_data)
+{
+       FILE *file = (FILE *)cb_data;
+       char *msg;
+       unsigned long msglen;
+       enum object_type type;
+       struct rev_note note;
+
+       if (!(msg = read_sha1_file(note_sha1, &type, &msglen)) ||
+                       !msglen || type != OBJ_BLOB) {
+               free(msg);
+               return 1;
+       }
+       if (parse_rev_note(msg, &note))
+               return 2;
+       if (fprintf(file, ":%d %s\n", note.rev_nr, sha1_to_hex(object_sha1)) < 1)
+               return 3;
+       return 0;
+}
+
+static void regenerate_marks(void)
+{
+       int ret;
+       FILE *marksfile = fopen(marksfilename, "w+");
+
+       if (!marksfile)
+               die_errno("Couldn't create mark file %s.", marksfilename);
+       ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
+       if (ret)
+               die("Regeneration of marks failed, returned %d.", ret);
+       fclose(marksfile);
+}
+
+static void check_or_regenerate_marks(int latestrev)
+{
+       FILE *marksfile;
+       struct strbuf sb = STRBUF_INIT;
+       struct strbuf line = STRBUF_INIT;
+       int found = 0;
+
+       if (latestrev < 1)
+               return;
+
+       init_notes(NULL, notes_ref, NULL, 0);
+       marksfile = fopen(marksfilename, "r");
+       if (!marksfile) {
+               regenerate_marks();
+               marksfile = fopen(marksfilename, "r");
+               if (!marksfile)
+                       die_errno("cannot read marks file %s!", marksfilename);
+               fclose(marksfile);
+       } else {
+               strbuf_addf(&sb, ":%d ", latestrev);
+               while (strbuf_getline(&line, marksfile, '\n') != EOF) {
+                       if (!prefixcmp(line.buf, sb.buf)) {
+                               found++;
+                               break;
+                       }
+               }
+               fclose(marksfile);
+               if (!found)
+                       regenerate_marks();
+       }
+       free_notes(NULL);
+       strbuf_release(&sb);
+       strbuf_release(&line);
+}
+
+static int cmd_import(const char *line)
+{
+       int code;
+       int dumpin_fd;
+       char *note_msg;
+       unsigned char head_sha1[20];
+       unsigned int startrev;
+       struct argv_array svndump_argv = ARGV_ARRAY_INIT;
+       struct child_process svndump_proc;
+
+       if (read_ref(private_ref, head_sha1))
+               startrev = 0;
+       else {
+               note_msg = read_ref_note(head_sha1);
+               if(note_msg == NULL) {
+                       warning("No note found for %s.", private_ref);
+                       startrev = 0;
+               } else {
+                       struct rev_note note = { 0 };
+                       if (parse_rev_note(note_msg, &note))
+                               die("Revision number couldn't be parsed from note.");
+                       startrev = note.rev_nr + 1;
+                       free(note_msg);
+               }
+       }
+       check_or_regenerate_marks(startrev - 1);
+
+       if (dump_from_file) {
+               dumpin_fd = open(url, O_RDONLY);
+               if(dumpin_fd < 0)
+                       die_errno("Couldn't open svn dump file %s.", url);
+       } else {
+               memset(&svndump_proc, 0, sizeof(struct child_process));
+               svndump_proc.out = -1;
+               argv_array_push(&svndump_argv, "svnrdump");
+               argv_array_push(&svndump_argv, "dump");
+               argv_array_push(&svndump_argv, url);
+               argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
+               svndump_proc.argv = svndump_argv.argv;
+
+               code = start_command(&svndump_proc);
+               if (code)
+                       die("Unable to start %s, code %d", svndump_proc.argv[0], code);
+               dumpin_fd = svndump_proc.out;
+       }
+       /* setup marks file import/export */
+       printf("feature import-marks-if-exists=%s\n"
+                       "feature export-marks=%s\n", marksfilename, marksfilename);
+
+       svndump_init_fd(dumpin_fd, STDIN_FILENO);
+       svndump_read(url, private_ref, notes_ref);
+       svndump_deinit();
+       svndump_reset();
+
+       close(dumpin_fd);
+       if (!dump_from_file) {
+               code = finish_command(&svndump_proc);
+               if (code)
+                       warning("%s, returned %d", svndump_proc.argv[0], code);
+               argv_array_clear(&svndump_argv);
+       }
+
+       return 0;
+}
+
+static int cmd_list(const char *line)
+{
+       printf("? %s\n\n", remote_ref);
+       fflush(stdout);
+       return 0;
+}
+
+static int do_command(struct strbuf *line)
+{
+       const struct input_command_entry *p = input_command_list;
+       static struct string_list batchlines = STRING_LIST_INIT_DUP;
+       static const struct input_command_entry *batch_cmd;
+       /*
+        * commands can be grouped together in a batch.
+        * Batches are ended by \n. If no batch is active the program ends.
+        * During a batch all lines are buffered and passed to the handler function
+        * when the batch is terminated.
+        */
+       if (line->len == 0) {
+               if (batch_cmd) {
+                       struct string_list_item *item;
+                       for_each_string_list_item(item, &batchlines)
+                               batch_cmd->fn(item->string);
+                       terminate_batch();
+                       batch_cmd = NULL;
+                       string_list_clear(&batchlines, 0);
+                       return 0;       /* end of the batch, continue reading other commands. */
+               }
+               return 1;       /* end of command stream, quit */
+       }
+       if (batch_cmd) {
+               if (prefixcmp(batch_cmd->name, line->buf))
+                       die("Active %s batch interrupted by %s", batch_cmd->name, line->buf);
+               /* buffer batch lines */
+               string_list_append(&batchlines, line->buf);
+               return 0;
+       }
+
+       for (p = input_command_list; p->name; p++) {
+               if (!prefixcmp(line->buf, p->name) && (strlen(p->name) == line->len ||
+                               line->buf[strlen(p->name)] == ' ')) {
+                       if (p->batchable) {
+                               batch_cmd = p;
+                               string_list_append(&batchlines, line->buf);
+                               return 0;
+                       }
+                       return p->fn(line->buf);
+               }
+       }
+       die("Unknown command '%s'\n", line->buf);
+       return 0;
+}
+
+int main(int argc, const char **argv)
+{
+       struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
+                       private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
+                       notes_ref_sb = STRBUF_INIT;
+       static struct remote *remote;
+       const char *url_in;
+
+       git_extract_argv0_path(argv[0]);
+       setup_git_directory();
+       if (argc < 2 || argc > 3) {
+               usage("git-remote-svn <remote-name> [<url>]");
+               return 1;
+       }
+
+       remote = remote_get(argv[1]);
+       url_in = (argc == 3) ? argv[2] : remote->url[0];
+
+       if (!prefixcmp(url_in, "file://")) {
+               dump_from_file = 1;
+               url = url_decode(url_in + sizeof("file://")-1);
+       } else {
+               dump_from_file = 0;
+               end_url_with_slash(&url_sb, url_in);
+               url = url_sb.buf;
+       }
+
+       strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name);
+       private_ref = private_ref_sb.buf;
+
+       strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
+       notes_ref = notes_ref_sb.buf;
+
+       strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks",
+               get_git_dir(), remote->name);
+       marksfilename = marksfilename_sb.buf;
+
+       while (1) {
+               if (strbuf_getline(&buf, stdin, '\n') == EOF) {
+                       if (ferror(stdin))
+                               die("Error reading command stream");
+                       else
+                               die("Unexpected end of command stream");
+               }
+               if (do_command(&buf))
+                       break;
+               strbuf_reset(&buf);
+       }
+
+       strbuf_release(&buf);
+       strbuf_release(&url_sb);
+       strbuf_release(&private_ref_sb);
+       strbuf_release(&notes_ref_sb);
+       strbuf_release(&marksfilename_sb);
+       return 0;
+}
index 04fd9ea..ca1f8f2 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);
@@ -1458,8 +1469,8 @@ int get_fetch_map(const struct ref *remote_refs,
 
        for (rmp = &ref_map; *rmp; ) {
                if ((*rmp)->peer_ref) {
-                       if (check_refname_format((*rmp)->peer_ref->name + 5,
-                               REFNAME_ALLOW_ONELEVEL)) {
+                       if (prefixcmp((*rmp)->peer_ref->name, "refs/") ||
+                           check_refname_format((*rmp)->peer_ref->name, 0)) {
                                struct ref *ignore = *rmp;
                                error("* Ignoring funny ref '%s' locally",
                                      (*rmp)->peer_ref->name);
@@ -1627,13 +1638,16 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 
        base = branch->merge[0]->dst;
        base = shorten_unambiguous_ref(base, 0);
-       if (!num_theirs)
+       if (!num_theirs) {
                strbuf_addf(sb,
                        Q_("Your branch is ahead of '%s' by %d commit.\n",
                           "Your branch is ahead of '%s' by %d commits.\n",
                           num_ours),
                        base, num_ours);
-       else if (!num_ours)
+               if (advice_status_hints)
+                       strbuf_addf(sb,
+                               _("  (use \"git push\" to publish your local commits)\n"));
+       } else if (!num_ours) {
                strbuf_addf(sb,
                        Q_("Your branch is behind '%s' by %d commit, "
                               "and can be fast-forwarded.\n",
@@ -1641,7 +1655,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                               "and can be fast-forwarded.\n",
                           num_theirs),
                        base, num_theirs);
-       else
+               if (advice_status_hints)
+                       strbuf_addf(sb,
+                               _("  (use \"git pull\" to update your local branch)\n"));
+       } else {
                strbuf_addf(sb,
                        Q_("Your branch and '%s' have diverged,\n"
                               "and have %d and %d different commit each, "
@@ -1651,6 +1668,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                               "respectively.\n",
                           num_theirs),
                        base, num_ours, num_theirs);
+               if (advice_status_hints)
+                       strbuf_addf(sb,
+                               _("  (use \"git pull\" to merge the remote branch into yours)\n"));
+       }
        return 1;
 }
 
index a09e60b..95d21e6 100644 (file)
@@ -1048,9 +1048,9 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 
        revs->commit_format = CMIT_FMT_DEFAULT;
 
+       init_grep_defaults();
+       grep_init(&revs->grep_filter, prefix);
        revs->grep_filter.status_only = 1;
-       revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list);
-       revs->grep_filter.header_tail = &(revs->grep_filter.header_list);
        revs->grep_filter.regflags = REG_NEWLINE;
 
        diff_setup(&revs->diffopt);
@@ -1603,13 +1603,17 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                return argcount;
        } else if (!strcmp(arg, "--grep-debug")) {
                revs->grep_filter.debug = 1;
+       } else if (!strcmp(arg, "--basic-regexp")) {
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_BRE, &revs->grep_filter);
        } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
-               revs->grep_filter.regflags |= REG_EXTENDED;
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, &revs->grep_filter);
        } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
                revs->grep_filter.regflags |= REG_ICASE;
                DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
        } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
-               revs->grep_filter.fixed = 1;
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_FIXED, &revs->grep_filter);
+       } else if (!strcmp(arg, "--perl-regexp")) {
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter);
        } else if (!strcmp(arg, "--all-match")) {
                revs->grep_filter.all_match = 1;
        } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
@@ -1893,6 +1897,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        revs->diffopt.abbrev = revs->abbrev;
        diff_setup_done(&revs->diffopt);
 
+       grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,
+                                &revs->grep_filter);
        compile_grep_patterns(&revs->grep_filter);
 
        if (revs->reverse && revs->reflog_info)
@@ -2236,7 +2242,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                if (!buf.len)
                        strbuf_addstr(&buf, commit->buffer);
                format_display_notes(commit->object.sha1, &buf,
-                                    get_log_output_encoding(), 0);
+                                    get_log_output_encoding(), 1);
        }
 
        /* Find either in the commit object, or in the temporary */
index a95bd0b..059bfff 100644 (file)
@@ -111,6 +111,7 @@ struct rev_info {
 
        /* Format info */
        unsigned int    shown_one:1,
+                       shown_dashes:1,
                        show_merge:1,
                        show_notes:1,
                        show_notes_given:1,
index 1101ef7..0471219 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);
                /*
@@ -397,16 +398,6 @@ fail_pipe:
                                        unsetenv(*cmd->env);
                        }
                }
-               if (cmd->preexec_cb) {
-                       /*
-                        * We cannot predict what the pre-exec callback does.
-                        * Forgo parent notification.
-                        */
-                       close(child_notifier);
-                       child_notifier = -1;
-
-                       cmd->preexec_cb();
-               }
                if (cmd->git_cmd) {
                        execv_git_cmd(cmd->argv);
                } else if (cmd->use_shell) {
@@ -442,8 +433,7 @@ fail_pipe:
                 * 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;
        }
@@ -548,7 +538,7 @@ fail_pipe:
 
 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)
@@ -735,7 +725,7 @@ error:
 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 44f7d2b..850c638 100644 (file)
@@ -39,7 +39,6 @@ struct child_process {
        unsigned stdout_to_stderr:1;
        unsigned use_shell:1;
        unsigned clean_on_exit:1;
-       void (*preexec_cb)(void);
 };
 
 int start_command(struct child_process *);
diff --git a/send-pack.c b/send-pack.c
new file mode 100644 (file)
index 0000000..f50dfd9
--- /dev/null
@@ -0,0 +1,344 @@
+#include "builtin.h"
+#include "commit.h"
+#include "refs.h"
+#include "pkt-line.h"
+#include "sideband.h"
+#include "run-command.h"
+#include "remote.h"
+#include "send-pack.h"
+#include "quote.h"
+#include "transport.h"
+#include "version.h"
+
+static int feed_object(const unsigned char *sha1, int fd, int negative)
+{
+       char buf[42];
+
+       if (negative && !has_sha1_file(sha1))
+               return 1;
+
+       memcpy(buf + negative, sha1_to_hex(sha1), 40);
+       if (negative)
+               buf[0] = '^';
+       buf[40 + negative] = '\n';
+       return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
+}
+
+/*
+ * Make a pack stream and spit it out into file descriptor fd
+ */
+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
+{
+       /*
+        * The child becomes pack-objects --revs; we feed
+        * the revision parameters to it via its stdin and
+        * let its stdout go back to the other end.
+        */
+       const char *argv[] = {
+               "pack-objects",
+               "--all-progress-implied",
+               "--revs",
+               "--stdout",
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+       };
+       struct child_process po;
+       int i;
+
+       i = 4;
+       if (args->use_thin_pack)
+               argv[i++] = "--thin";
+       if (args->use_ofs_delta)
+               argv[i++] = "--delta-base-offset";
+       if (args->quiet || !args->progress)
+               argv[i++] = "-q";
+       if (args->progress)
+               argv[i++] = "--progress";
+       memset(&po, 0, sizeof(po));
+       po.argv = argv;
+       po.in = -1;
+       po.out = args->stateless_rpc ? -1 : fd;
+       po.git_cmd = 1;
+       if (start_command(&po))
+               die_errno("git pack-objects failed");
+
+       /*
+        * We feed the pack-objects we just spawned with revision
+        * parameters by writing to the pipe.
+        */
+       for (i = 0; i < extra->nr; i++)
+               if (!feed_object(extra->array[i], po.in, 1))
+                       break;
+
+       while (refs) {
+               if (!is_null_sha1(refs->old_sha1) &&
+                   !feed_object(refs->old_sha1, po.in, 1))
+                       break;
+               if (!is_null_sha1(refs->new_sha1) &&
+                   !feed_object(refs->new_sha1, po.in, 0))
+                       break;
+               refs = refs->next;
+       }
+
+       close(po.in);
+
+       if (args->stateless_rpc) {
+               char *buf = xmalloc(LARGE_PACKET_MAX);
+               while (1) {
+                       ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
+                       if (n <= 0)
+                               break;
+                       send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
+               }
+               free(buf);
+               close(po.out);
+               po.out = -1;
+       }
+
+       if (finish_command(&po))
+               return -1;
+       return 0;
+}
+
+static int receive_status(int in, struct ref *refs)
+{
+       struct ref *hint;
+       char line[1000];
+       int ret = 0;
+       int len = packet_read_line(in, line, sizeof(line));
+       if (len < 10 || memcmp(line, "unpack ", 7))
+               return error("did not receive remote status");
+       if (memcmp(line, "unpack ok\n", 10)) {
+               char *p = line + strlen(line) - 1;
+               if (*p == '\n')
+                       *p = '\0';
+               error("unpack failed: %s", line + 7);
+               ret = -1;
+       }
+       hint = NULL;
+       while (1) {
+               char *refname;
+               char *msg;
+               len = packet_read_line(in, line, sizeof(line));
+               if (!len)
+                       break;
+               if (len < 3 ||
+                   (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
+                       fprintf(stderr, "protocol error: %s\n", line);
+                       ret = -1;
+                       break;
+               }
+
+               line[strlen(line)-1] = '\0';
+               refname = line + 3;
+               msg = strchr(refname, ' ');
+               if (msg)
+                       *msg++ = '\0';
+
+               /* first try searching at our hint, falling back to all refs */
+               if (hint)
+                       hint = find_ref_by_name(hint, refname);
+               if (!hint)
+                       hint = find_ref_by_name(refs, refname);
+               if (!hint) {
+                       warning("remote reported status on unknown ref: %s",
+                                       refname);
+                       continue;
+               }
+               if (hint->status != REF_STATUS_EXPECTING_REPORT) {
+                       warning("remote reported status on unexpected ref: %s",
+                                       refname);
+                       continue;
+               }
+
+               if (line[0] == 'o' && line[1] == 'k')
+                       hint->status = REF_STATUS_OK;
+               else {
+                       hint->status = REF_STATUS_REMOTE_REJECT;
+                       ret = -1;
+               }
+               if (msg)
+                       hint->remote_status = xstrdup(msg);
+               /* start our next search from the next ref */
+               hint = hint->next;
+       }
+       return ret;
+}
+
+static int sideband_demux(int in, int out, void *data)
+{
+       int *fd = data, ret;
+#ifdef NO_PTHREADS
+       close(fd[1]);
+#endif
+       ret = recv_sideband("send-pack", fd[0], out);
+       close(out);
+       return ret;
+}
+
+int send_pack(struct send_pack_args *args,
+             int fd[], struct child_process *conn,
+             struct ref *remote_refs,
+             struct extra_have_objects *extra_have)
+{
+       int in = fd[0];
+       int out = fd[1];
+       struct strbuf req_buf = STRBUF_INIT;
+       struct ref *ref;
+       int new_refs;
+       int allow_deleting_refs = 0;
+       int status_report = 0;
+       int use_sideband = 0;
+       int quiet_supported = 0;
+       int agent_supported = 0;
+       unsigned cmds_sent = 0;
+       int ret;
+       struct async demux;
+
+       /* Does the other end support the reporting? */
+       if (server_supports("report-status"))
+               status_report = 1;
+       if (server_supports("delete-refs"))
+               allow_deleting_refs = 1;
+       if (server_supports("ofs-delta"))
+               args->use_ofs_delta = 1;
+       if (server_supports("side-band-64k"))
+               use_sideband = 1;
+       if (server_supports("quiet"))
+               quiet_supported = 1;
+       if (server_supports("agent"))
+               agent_supported = 1;
+
+       if (!remote_refs) {
+               fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
+                       "Perhaps you should specify a branch such as 'master'.\n");
+               return 0;
+       }
+
+       /*
+        * Finally, tell the other end!
+        */
+       new_refs = 0;
+       for (ref = remote_refs; ref; ref = ref->next) {
+               if (!ref->peer_ref && !args->send_mirror)
+                       continue;
+
+               /* Check for statuses set by set_ref_status_for_push() */
+               switch (ref->status) {
+               case REF_STATUS_REJECT_NONFASTFORWARD:
+               case REF_STATUS_UPTODATE:
+                       continue;
+               default:
+                       ; /* do nothing */
+               }
+
+               if (ref->deletion && !allow_deleting_refs) {
+                       ref->status = REF_STATUS_REJECT_NODELETE;
+                       continue;
+               }
+
+               if (!ref->deletion)
+                       new_refs++;
+
+               if (args->dry_run) {
+                       ref->status = REF_STATUS_OK;
+               } else {
+                       char *old_hex = sha1_to_hex(ref->old_sha1);
+                       char *new_hex = sha1_to_hex(ref->new_sha1);
+                       int quiet = quiet_supported && (args->quiet || !args->progress);
+
+                       if (!cmds_sent && (status_report || use_sideband ||
+                                          quiet || agent_supported)) {
+                               packet_buf_write(&req_buf,
+                                                "%s %s %s%c%s%s%s%s%s",
+                                                old_hex, new_hex, ref->name, 0,
+                                                status_report ? " report-status" : "",
+                                                use_sideband ? " side-band-64k" : "",
+                                                quiet ? " quiet" : "",
+                                                agent_supported ? " agent=" : "",
+                                                agent_supported ? git_user_agent_sanitized() : ""
+                                               );
+                       }
+                       else
+                               packet_buf_write(&req_buf, "%s %s %s",
+                                                old_hex, new_hex, ref->name);
+                       ref->status = status_report ?
+                               REF_STATUS_EXPECTING_REPORT :
+                               REF_STATUS_OK;
+                       cmds_sent++;
+               }
+       }
+
+       if (args->stateless_rpc) {
+               if (!args->dry_run && cmds_sent) {
+                       packet_buf_flush(&req_buf);
+                       send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
+               }
+       } else {
+               safe_write(out, req_buf.buf, req_buf.len);
+               packet_flush(out);
+       }
+       strbuf_release(&req_buf);
+
+       if (use_sideband && cmds_sent) {
+               memset(&demux, 0, sizeof(demux));
+               demux.proc = sideband_demux;
+               demux.data = fd;
+               demux.out = -1;
+               if (start_async(&demux))
+                       die("send-pack: unable to fork off sideband demultiplexer");
+               in = demux.out;
+       }
+
+       if (new_refs && cmds_sent) {
+               if (pack_objects(out, remote_refs, extra_have, args) < 0) {
+                       for (ref = remote_refs; ref; ref = ref->next)
+                               ref->status = REF_STATUS_NONE;
+                       if (args->stateless_rpc)
+                               close(out);
+                       if (git_connection_is_socket(conn))
+                               shutdown(fd[0], SHUT_WR);
+                       if (use_sideband)
+                               finish_async(&demux);
+                       return -1;
+               }
+       }
+       if (args->stateless_rpc && cmds_sent)
+               packet_flush(out);
+
+       if (status_report && cmds_sent)
+               ret = receive_status(in, remote_refs);
+       else
+               ret = 0;
+       if (args->stateless_rpc)
+               packet_flush(out);
+
+       if (use_sideband && cmds_sent) {
+               if (finish_async(&demux)) {
+                       error("error in sideband demultiplexer");
+                       ret = -1;
+               }
+               close(demux.out);
+       }
+
+       if (ret < 0)
+               return ret;
+
+       if (args->porcelain)
+               return 0;
+
+       for (ref = remote_refs; ref; ref = ref->next) {
+               switch (ref->status) {
+               case REF_STATUS_NONE:
+               case REF_STATUS_UPTODATE:
+               case REF_STATUS_OK:
+                       break;
+               default:
+                       return -1;
+               }
+       }
+       return 0;
+}
index e3723d2..aef5e8a 100644 (file)
@@ -60,7 +60,7 @@ static int get_message(struct commit *commit, struct commit_message *out)
 
        out->reencoded_message = NULL;
        out->message = commit->buffer;
-       if (strcmp(encoding, git_commit_encoding))
+       if (same_encoding(encoding, git_commit_encoding))
                out->reencoded_message = reencode_string(commit->buffer,
                                        git_commit_encoding, encoding);
        if (out->reencoded_message)
@@ -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))
+       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 3a1b2fd..f108c4b 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;
@@ -621,16 +622,38 @@ static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_
 }
 
 /*
+ * 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.
  */
 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 9152974..40b2329 100644 (file)
@@ -7,6 +7,7 @@
  * creation etc.
  */
 #include "cache.h"
+#include "string-list.h"
 #include "delta.h"
 #include "pack.h"
 #include "blob.h"
@@ -246,7 +247,7 @@ static int git_open_noatime(const char *name);
  * SHA1, an extra slash for the first level indirection, and the
  * terminating NUL.
  */
-static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
+static int link_alt_odb_entry(const char *entry, const char *relative_base, int depth)
 {
        const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
@@ -258,7 +259,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative
                strbuf_addstr(&pathbuf, real_path(relative_base));
                strbuf_addch(&pathbuf, '/');
        }
-       strbuf_add(&pathbuf, entry, len);
+       strbuf_addstr(&pathbuf, entry);
 
        normalize_path_copy(pathbuf.buf, pathbuf.buf);
 
@@ -316,10 +317,12 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative
        return 0;
 }
 
-static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
+static void link_alt_odb_entries(const char *alt, int len, int sep,
                                 const char *relative_base, int depth)
 {
-       const char *cp, *last;
+       struct string_list entries = STRING_LIST_INIT_NODUP;
+       char *alt_copy;
+       int i;
 
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
@@ -327,30 +330,21 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
                return;
        }
 
-       last = alt;
-       while (last < ep) {
-               cp = last;
-               if (cp < ep && *cp == '#') {
-                       while (cp < ep && *cp != sep)
-                               cp++;
-                       last = cp + 1;
+       alt_copy = xmemdupz(alt, len);
+       string_list_split_in_place(&entries, alt_copy, sep, -1);
+       for (i = 0; i < entries.nr; i++) {
+               const char *entry = entries.items[i].string;
+               if (entry[0] == '\0' || entry[0] == '#')
                        continue;
+               if (!is_absolute_path(entry) && depth) {
+                       error("%s: ignoring relative alternate object store %s",
+                                       relative_base, entry);
+               } else {
+                       link_alt_odb_entry(entry, relative_base, depth);
                }
-               while (cp < ep && *cp != sep)
-                       cp++;
-               if (last != cp) {
-                       if (!is_absolute_path(last) && depth) {
-                               error("%s: ignoring relative alternate object store %s",
-                                               relative_base, last);
-                       } else {
-                               link_alt_odb_entry(last, cp - last,
-                                               relative_base, depth);
-                       }
-               }
-               while (cp < ep && *cp == sep)
-                       cp++;
-               last = cp;
        }
+       string_list_clear(&entries, 0);
+       free(alt_copy);
 }
 
 void read_info_alternates(const char * relative_base, int depth)
@@ -377,7 +371,7 @@ void read_info_alternates(const char * relative_base, int depth)
        map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
 
-       link_alt_odb_entries(map, map + mapsz, '\n', relative_base, depth);
+       link_alt_odb_entries(map, mapsz, '\n', relative_base, depth);
 
        munmap(map, mapsz);
 }
@@ -391,7 +385,7 @@ void add_to_alternates_file(const char *reference)
        if (commit_lock_file(lock))
                die("could not close alternates file");
        if (alt_odb_tail)
-               link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0);
+               link_alt_odb_entries(alt, strlen(alt), '\n', NULL, 0);
 }
 
 void foreach_alt_odb(alt_odb_fn fn, void *cb)
@@ -415,7 +409,7 @@ void prepare_alt_odb(void)
        if (!alt) alt = "";
 
        alt_odb_tail = &alt_odb_list;
-       link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0);
+       link_alt_odb_entries(alt, strlen(alt), PATH_SEP, NULL, 0);
 
        read_info_alternates(get_object_directory(), 0);
 }
index 0510f76..05d0693 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -44,7 +44,9 @@ void strbuf_release(struct strbuf *sb)
 
 char *strbuf_detach(struct strbuf *sb, size_t *sz)
 {
-       char *res = sb->alloc ? sb->buf : NULL;
+       char *res;
+       strbuf_grow(sb, 0);
+       res = sb->buf;
        if (sz)
                *sz = sb->len;
        strbuf_init(sb, 0);
@@ -104,35 +106,30 @@ void strbuf_ltrim(struct strbuf *sb)
        sb->buf[sb->len] = '\0';
 }
 
-struct strbuf **strbuf_split_buf(const char *str, size_t slen, int delim, int max)
+struct strbuf **strbuf_split_buf(const char *str, size_t slen,
+                                int terminator, int max)
 {
-       int alloc = 2, pos = 0;
-       const char *n, *p;
-       struct strbuf **ret;
+       struct strbuf **ret = NULL;
+       size_t nr = 0, alloc = 0;
        struct strbuf *t;
 
-       ret = xcalloc(alloc, sizeof(struct strbuf *));
-       p = n = str;
-       while (n < str + slen) {
-               int len;
-               if (max <= 0 || pos + 1 < max)
-                       n = memchr(n, delim, slen - (n - str));
-               else
-                       n = NULL;
-               if (pos + 1 >= alloc) {
-                       alloc = alloc * 2;
-                       ret = xrealloc(ret, sizeof(struct strbuf *) * alloc);
+       while (slen) {
+               int len = slen;
+               if (max <= 0 || nr + 1 < max) {
+                       const char *end = memchr(str, terminator, slen);
+                       if (end)
+                               len = end - str + 1;
                }
-               if (!n)
-                       n = str + slen - 1;
-               len = n - p + 1;
                t = xmalloc(sizeof(struct strbuf));
                strbuf_init(t, len);
-               strbuf_add(t, p, len);
-               ret[pos] = t;
-               ret[++pos] = NULL;
-               p = ++n;
+               strbuf_add(t, str, len);
+               ALLOC_GROW(ret, nr + 2, alloc);
+               ret[nr++] = t;
+               str += len;
+               slen -= len;
        }
+       ALLOC_GROW(ret, nr + 1, alloc); /* In case string was empty */
+       ret[nr] = NULL;
        return ret;
 }
 
index be941ee..aa386c6 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -44,22 +44,56 @@ extern void strbuf_rtrim(struct strbuf *);
 extern void strbuf_ltrim(struct strbuf *);
 extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
 
+/*
+ * Split str (of length slen) at the specified terminator character.
+ * Return a null-terminated array of pointers to strbuf objects
+ * holding the substrings.  The substrings include the terminator,
+ * except for the last substring, which might be unterminated if the
+ * original string did not end with a terminator.  If max is positive,
+ * then split the string into at most max substrings (with the last
+ * substring containing everything following the (max-1)th terminator
+ * character).
+ *
+ * For lighter-weight alternatives, see string_list_split() and
+ * string_list_split_in_place().
+ */
 extern struct strbuf **strbuf_split_buf(const char *, size_t,
-                                       int delim, int max);
+                                       int terminator, int max);
+
+/*
+ * Split a NUL-terminated string at the specified terminator
+ * character.  See strbuf_split_buf() for more information.
+ */
 static inline struct strbuf **strbuf_split_str(const char *str,
-                                              int delim, int max)
+                                              int terminator, int max)
 {
-       return strbuf_split_buf(str, strlen(str), delim, max);
+       return strbuf_split_buf(str, strlen(str), terminator, max);
 }
+
+/*
+ * Split a strbuf at the specified terminator character.  See
+ * strbuf_split_buf() for more information.
+ */
 static inline struct strbuf **strbuf_split_max(const struct strbuf *sb,
-                                               int delim, int max)
+                                               int terminator, int max)
 {
-       return strbuf_split_buf(sb->buf, sb->len, delim, max);
+       return strbuf_split_buf(sb->buf, sb->len, terminator, max);
 }
-static inline struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
+
+/*
+ * Split a strbuf at the specified terminator character.  See
+ * strbuf_split_buf() for more information.
+ */
+static inline struct strbuf **strbuf_split(const struct strbuf *sb,
+                                          int terminator)
 {
-       return strbuf_split_max(sb, delim, 0);
+       return strbuf_split_max(sb, terminator, 0);
 }
+
+/*
+ * Free a NULL-terminated list of strbufs (for example, the return
+ * values of the strbuf_split*() functions).
+ */
 extern void strbuf_list_free(struct strbuf **);
 
 /*----- add data in your buffer -----*/
index c54b816..480173f 100644 (file)
@@ -136,24 +136,13 @@ void filter_string_list(struct string_list *list, int free_util,
        list->nr = dst;
 }
 
-char *string_list_longest_prefix(const struct string_list *prefixes,
-                                const char *string)
+static int item_is_not_empty(struct string_list_item *item, void *unused)
 {
-       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 *item->string != '\0';
+}
 
-       return retval;
+void string_list_remove_empty_items(struct string_list *list, int free_util) {
+       filter_string_list(list, free_util, item_is_not_empty, NULL);
 }
 
 void string_list_clear(struct string_list *list, int free_util)
index 5efd07b..db12848 100644 (file)
@@ -39,13 +39,11 @@ void filter_string_list(struct string_list *list, int free_util,
                        string_list_each_func_t want, void *cb_data);
 
 /*
- * 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).
+ * Remove any empty strings from the list.  If free_util is true, call
+ * free() on the util members of any items that have to be deleted.
+ * Preserve the order of the items that are retained.
  */
-char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
-
+void string_list_remove_empty_items(struct string_list *list, int free_util);
 
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
index 50f213e..2f55436 100644 (file)
@@ -258,7 +258,7 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
 
 void show_submodule_summary(FILE *f, const char *path,
                unsigned char one[20], unsigned char two[20],
-               unsigned dirty_submodule,
+               unsigned dirty_submodule, const char *meta,
                const char *del, const char *add, const char *reset)
 {
        struct rev_info rev;
@@ -292,15 +292,15 @@ void show_submodule_summary(FILE *f, const char *path,
                return;
        }
 
-       strbuf_addf(&sb, "Submodule %s %s..", path,
+       strbuf_addf(&sb, "%sSubmodule %s %s..", meta, path,
                        find_unique_abbrev(one, DEFAULT_ABBREV));
        if (!fast_backward && !fast_forward)
                strbuf_addch(&sb, '.');
        strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
        if (message)
-               strbuf_addf(&sb, " %s\n", message);
+               strbuf_addf(&sb, " %s%s\n", message, reset);
        else
-               strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
+               strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset);
        fwrite(sb.buf, sb.len, 1, f);
 
        if (!message) {
@@ -759,6 +759,86 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        return dirty_submodule;
 }
 
+int submodule_uses_gitfile(const char *path)
+{
+       struct child_process cp;
+       const char *argv[] = {
+               "submodule",
+               "foreach",
+               "--quiet",
+               "--recursive",
+               "test -f .git",
+               NULL,
+       };
+       struct strbuf buf = STRBUF_INIT;
+       const char *git_dir;
+
+       strbuf_addf(&buf, "%s/.git", path);
+       git_dir = read_gitfile(buf.buf);
+       if (!git_dir) {
+               strbuf_release(&buf);
+               return 0;
+       }
+       strbuf_release(&buf);
+
+       /* Now test that all nested submodules use a gitfile too */
+       memset(&cp, 0, sizeof(cp));
+       cp.argv = argv;
+       cp.env = local_repo_env;
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       cp.no_stderr = 1;
+       cp.no_stdout = 1;
+       cp.dir = path;
+       if (run_command(&cp))
+               return 0;
+
+       return 1;
+}
+
+int ok_to_remove_submodule(const char *path)
+{
+       struct stat st;
+       ssize_t len;
+       struct child_process cp;
+       const char *argv[] = {
+               "status",
+               "--porcelain",
+               "-u",
+               "--ignore-submodules=none",
+               NULL,
+       };
+       struct strbuf buf = STRBUF_INIT;
+       int ok_to_remove = 1;
+
+       if ((lstat(path, &st) < 0) || is_empty_dir(path))
+               return 1;
+
+       if (!submodule_uses_gitfile(path))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.argv = argv;
+       cp.env = local_repo_env;
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       cp.out = -1;
+       cp.dir = path;
+       if (start_command(&cp))
+               die("Could not run 'git status --porcelain -uall --ignore-submodules=none' in submodule %s", path);
+
+       len = strbuf_read(&buf, cp.out, 1024);
+       if (len > 2)
+               ok_to_remove = 0;
+       close(cp.out);
+
+       if (finish_command(&cp))
+               die("'git status --porcelain -uall --ignore-submodules=none' failed in submodule %s", path);
+
+       strbuf_release(&buf);
+       return ok_to_remove;
+}
+
 static int find_first_merges(struct object_array *result, const char *path,
                struct commit *a, struct commit *b)
 {
index 594b50d..3dc1b3f 100644 (file)
@@ -20,7 +20,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
 void show_submodule_summary(FILE *f, const char *path,
                unsigned char one[20], unsigned char two[20],
-               unsigned dirty_submodule,
+               unsigned dirty_submodule, const char *meta,
                const char *del, const char *add, const char *reset);
 void set_config_fetch_recurse_submodules(int value);
 void check_for_new_submodule_commits(unsigned char new_sha1[20]);
@@ -28,6 +28,8 @@ int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
                               int quiet);
 unsigned is_submodule_modified(const char *path, int ignore_untracked);
+int submodule_uses_gitfile(const char *path);
+int ok_to_remove_submodule(const char *path);
 int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],
                    const unsigned char a[20], const unsigned char b[20], int search);
 int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,
index 88e289f..5c6de81 100644 (file)
@@ -6,13 +6,14 @@
 -include ../config.mak.autogen
 -include ../config.mak
 
-#GIT_TEST_OPTS=--verbose --debug
+#GIT_TEST_OPTS = --verbose --debug
 SHELL_PATH ?= $(SHELL)
 PERL_PATH ?= /usr/bin/perl
 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 0f76f6c..ae8883a 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 49d5d87..fe76e84 100644 (file)
@@ -99,6 +99,13 @@ SSLEngine On
        Require valid-user
 </LocationMatch>
 
+<LocationMatch "^/auth-fetch/.*/git-upload-pack$">
+       AuthType Basic
+       AuthName "git-auth"
+       AuthUserFile passwd
+       Require valid-user
+</LocationMatch>
+
 <IfDefine DAV>
        LoadModule dav_module modules/mod_dav.so
        LoadModule dav_fs_module modules/mod_dav_fs.so
index 08677df..562cf41 100755 (executable)
@@ -115,6 +115,38 @@ then
        exit 1
 fi
 
+test_lazy_prereq LAZY_TRUE true
+havetrue=no
+test_expect_success LAZY_TRUE 'test runs if lazy prereq is satisfied' '
+       havetrue=yes
+'
+donthavetrue=yes
+test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' '
+       donthavetrue=no
+'
+
+if test "$havetrue$donthavetrue" != yesyes
+then
+       say 'bug in test framework: lazy prerequisites do not work'
+       exit 1
+fi
+
+test_lazy_prereq LAZY_FALSE false
+nothavefalse=no
+test_expect_success !LAZY_FALSE 'negative lazy prereqs checked' '
+       nothavefalse=yes
+'
+havefalse=yes
+test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' '
+       havefalse=no
+'
+
+if test "$nothavefalse$havefalse" != yesyes
+then
+       say 'bug in test framework: negative lazy prerequisites do not work'
+       exit 1
+fi
+
 clean=no
 test_expect_success 'tests clean up after themselves' '
        test_when_finished clean=yes
index febc45c..807b8b8 100755 (executable)
@@ -196,6 +196,16 @@ test_expect_success 'root subdir attribute test' '
        attr_check subdir/a/i unspecified
 '
 
+test_expect_success 'negative patterns' '
+       echo "!f test=bar" >.gitattributes &&
+       test_must_fail git check-attr test -- f
+'
+
+test_expect_success 'patterns starting with exclamation' '
+       echo "\!f test=foo" >.gitattributes &&
+       attr_check "!f" foo
+'
+
 test_expect_success 'setup bare' '
        git clone --bare . bare.git &&
        cd bare.git
diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh
new file mode 100755 (executable)
index 0000000..5868a87
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+test_description='basic sanity checks for git var'
+. ./test-lib.sh
+
+test_expect_success 'get GIT_AUTHOR_IDENT' '
+       test_tick &&
+       echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
+       git var GIT_AUTHOR_IDENT >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'get GIT_COMMITTER_IDENT' '
+       test_tick &&
+       echo "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" >expect &&
+       git var GIT_COMMITTER_IDENT >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success !AUTOIDENT 'requested identites are strict' '
+       (
+               sane_unset GIT_COMMITTER_NAME &&
+               sane_unset GIT_COMMITTER_EMAIL &&
+               test_must_fail git var GIT_COMMITTER_IDENT
+       )
+'
+
+# For git var -l, we check only a representative variable;
+# testing the whole output would make our test too brittle with
+# respect to unrelated changes in the test suite's environment.
+test_expect_success 'git var -l lists variables' '
+       git var -l >actual &&
+       echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
+       sed -n s/GIT_AUTHOR_IDENT=//p <actual >actual.author &&
+       test_cmp expect actual.author
+'
+
+test_expect_success 'git var -l lists config' '
+       git var -l >actual &&
+       echo false >expect &&
+       sed -n s/core\\.bare=//p <actual >actual.bare &&
+       test_cmp expect actual.bare
+'
+
+test_expect_success 'listing and asking for variables are exclusive' '
+       test_must_fail git var -l GIT_COMMITTER_IDENT
+'
+
+test_done
index ec6c1b3..5378787 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 78816d9..05d78d2 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 4ef2345..09a42a4 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 41c8826..dbfc05e 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 e23ac0e..1e2945e 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 e127f35..3c96fda 100755 (executable)
@@ -55,11 +55,13 @@ test_expect_success 'uppercase section' '
        test_cmp expect .git/config
 '
 
-test_expect_success 'replace with non-match' \
-       'git config core.penguin kingpin !blue'
+test_expect_success 'replace with non-match' '
+       git config core.penguin kingpin !blue
+'
 
-test_expect_success 'replace with non-match (actually matching)' \
-       'git config core.penguin "very blue" !kingpin'
+test_expect_success 'replace with non-match (actually matching)' '
+       git config core.penguin "very blue" !kingpin
+'
 
 cat > expect << EOF
 [core]
@@ -108,8 +110,9 @@ baz = multiple \
 lines
 EOF
 
-test_expect_success 'unset with cont. lines' \
-       'git config --unset beta.baz'
+test_expect_success 'unset with cont. lines' '
+       git config --unset beta.baz
+'
 
 cat > expect <<\EOF
 [alpha]
@@ -133,8 +136,9 @@ EOF
 
 cp .git/config .git/config2
 
-test_expect_success 'multiple unset' \
-       'git config --unset-all beta.haha'
+test_expect_success 'multiple unset' '
+       git config --unset-all beta.haha
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -145,7 +149,9 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config'
+test_expect_success 'multiple unset is correct' '
+       test_cmp expect .git/config
+'
 
 cp .git/config2 .git/config
 
@@ -156,8 +162,9 @@ test_expect_success '--replace-all missing value' '
 
 rm .git/config2
 
-test_expect_success '--replace-all' \
-       'git config --replace-all beta.haha gamma'
+test_expect_success '--replace-all' '
+       git config --replace-all beta.haha gamma
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -169,7 +176,9 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'all replaced' 'test_cmp expect .git/config'
+test_expect_success 'all replaced' '
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -200,7 +209,11 @@ test_expect_success 'really really mean test' '
        test_cmp expect .git/config
 '
 
-test_expect_success 'get value' 'test alpha = $(git config beta.haha)'
+test_expect_success 'get value' '
+       echo alpha >expect &&
+       git config beta.haha >actual &&
+       test_cmp expect actual
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -231,18 +244,30 @@ test_expect_success 'multivar' '
        test_cmp expect .git/config
 '
 
-test_expect_success 'non-match' \
-       'git config --get nextsection.nonewline !for'
+test_expect_success 'non-match' '
+       git config --get nextsection.nonewline !for
+'
 
-test_expect_success 'non-match value' \
-       'test wow = $(git config --get nextsection.nonewline !for)'
+test_expect_success 'non-match value' '
+       echo wow >expect &&
+       git config --get nextsection.nonewline !for >actual &&
+       test_cmp expect actual
+'
 
-test_expect_success 'ambiguous get' '
-       test_must_fail git config --get nextsection.nonewline
+test_expect_success 'multi-valued get returns final one' '
+       echo "wow2 for me" >expect &&
+       git config --get nextsection.nonewline >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success 'get multivar' \
-       'git config --get-all nextsection.nonewline'
+test_expect_success 'multi-valued get-all returns all' '
+       cat >expect <<-\EOF &&
+       wow
+       wow2 for me
+       EOF
+       git config --get-all nextsection.nonewline >actual &&
+       test_cmp expect actual
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -259,10 +284,6 @@ test_expect_success 'multivar replace' '
        test_cmp expect .git/config
 '
 
-test_expect_success 'ambiguous value' '
-       test_must_fail git config nextsection.nonewline
-'
-
 test_expect_success 'ambiguous unset' '
        test_must_fail git config --unset nextsection.nonewline
 '
@@ -290,8 +311,9 @@ test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla'
 
 test_expect_success 'correct key' 'git config 123456.a123 987'
 
-test_expect_success 'hierarchical section' \
-       'git config Version.1.2.3eX.Alpha beta'
+test_expect_success 'hierarchical section' '
+       git config Version.1.2.3eX.Alpha beta
+'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -307,7 +329,9 @@ noIndent= sillyValue ; 'nother silly comment
        Alpha = beta
 EOF
 
-test_expect_success 'hierarchical section value' 'test_cmp expect .git/config'
+test_expect_success 'hierarchical section value' '
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 beta.noindent=sillyValue
@@ -316,9 +340,10 @@ nextsection.nonewline=wow2 for me
 version.1.2.3eX.alpha=beta
 EOF
 
-test_expect_success 'working --list' \
-       'git config --list > output && cmp output expect'
-
+test_expect_success 'working --list' '
+       git config --list > output &&
+       test_cmp expect output
+'
 cat > expect << EOF
 EOF
 
@@ -332,8 +357,10 @@ beta.noindent sillyValue
 nextsection.nonewline wow2 for me
 EOF
 
-test_expect_success '--get-regexp' \
-       'git config --get-regexp in > output && cmp output expect'
+test_expect_success '--get-regexp' '
+       git config --get-regexp in >output &&
+       test_cmp expect output
+'
 
 cat > expect << EOF
 wow2 for me
@@ -353,41 +380,48 @@ cat > .git/config << EOF
        variable =
 EOF
 
-test_expect_success 'get variable with no value' \
-       'git config --get novalue.variable ^$'
+test_expect_success 'get variable with no value' '
+       git config --get novalue.variable ^$
+'
 
-test_expect_success 'get variable with empty value' \
-       'git config --get emptyvalue.variable ^$'
+test_expect_success 'get variable with empty value' '
+       git config --get emptyvalue.variable ^$
+'
 
 echo novalue.variable > expect
 
-test_expect_success 'get-regexp variable with no value' \
-       'git config --get-regexp novalue > output &&
-        cmp output expect'
+test_expect_success 'get-regexp variable with no value' '
+       git config --get-regexp novalue > output &&
+       test_cmp expect output
+'
 
 echo 'novalue.variable true' > expect
 
-test_expect_success 'get-regexp --bool variable with no value' \
-       'git config --bool --get-regexp novalue > output &&
-        cmp output expect'
+test_expect_success 'get-regexp --bool variable with no value' '
+       git config --bool --get-regexp novalue > output &&
+       test_cmp expect output
+'
 
 echo 'emptyvalue.variable ' > expect
 
-test_expect_success 'get-regexp variable with empty value' \
-       'git config --get-regexp emptyvalue > output &&
-        cmp output expect'
+test_expect_success 'get-regexp variable with empty value' '
+       git config --get-regexp emptyvalue > output &&
+       test_cmp expect output
+'
 
 echo true > expect
 
-test_expect_success 'get bool variable with no value' \
-       'git config --bool novalue.variable > output &&
-        cmp output expect'
+test_expect_success 'get bool variable with no value' '
+       git config --bool novalue.variable > output &&
+       test_cmp expect output
+'
 
 echo false > expect
 
-test_expect_success 'get bool variable with empty value' \
-       'git config --bool emptyvalue.variable > output &&
-        cmp output expect'
+test_expect_success 'get bool variable with empty value' '
+       git config --bool emptyvalue.variable > output &&
+       test_cmp expect output
+'
 
 test_expect_success 'no arguments, but no crash' '
        test_must_fail git config >output 2>&1 &&
@@ -427,8 +461,9 @@ test_expect_success 'new variable inserts into proper section' '
        test_cmp expect .git/config
 '
 
-test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \
-       'test_must_fail git config --file non-existing-config -l'
+test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' '
+       test_must_fail git config --file non-existing-config -l
+'
 
 cat > other-config << EOF
 [ein]
@@ -444,8 +479,10 @@ test_expect_success 'alternative GIT_CONFIG' '
        test_cmp expect output
 '
 
-test_expect_success 'alternative GIT_CONFIG (--file)' \
-       'git config --file other-config -l > output && cmp output expect'
+test_expect_success 'alternative GIT_CONFIG (--file)' '
+       git config --file other-config -l > output &&
+       test_cmp expect output
+'
 
 test_expect_success 'refer config from subdirectory' '
        mkdir x &&
@@ -489,8 +526,9 @@ cat > .git/config << EOF
 weird
 EOF
 
-test_expect_success "rename section" \
-       "git config --rename-section branch.eins branch.zwei"
+test_expect_success 'rename section' '
+       git config --rename-section branch.eins branch.zwei
+'
 
 cat > expect << EOF
 # Hallo
@@ -503,17 +541,22 @@ cat > expect << EOF
 weird
 EOF
 
-test_expect_success "rename succeeded" "test_cmp expect .git/config"
+test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+'
 
-test_expect_success "rename non-existing section" '
+test_expect_success 'rename non-existing section' '
        test_must_fail git config --rename-section \
                branch."world domination" branch.drei
 '
 
-test_expect_success "rename succeeded" "test_cmp expect .git/config"
+test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+'
 
-test_expect_success "rename another section" \
-       'git config --rename-section branch."1 234 blabl/a" branch.drei'
+test_expect_success 'rename another section' '
+       git config --rename-section branch."1 234 blabl/a" branch.drei
+'
 
 cat > expect << EOF
 # Hallo
@@ -526,14 +569,17 @@ cat > expect << EOF
 weird
 EOF
 
-test_expect_success "rename succeeded" "test_cmp expect .git/config"
+test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+'
 
 cat >> .git/config << EOF
 [branch "vier"] z = 1
 EOF
 
-test_expect_success "rename a section with a var on the same line" \
-       'git config --rename-section branch.vier branch.zwei'
+test_expect_success 'rename a section with a var on the same line' '
+       git config --rename-section branch.vier branch.zwei
+'
 
 cat > expect << EOF
 # Hallo
@@ -548,7 +594,9 @@ weird
        z = 1
 EOF
 
-test_expect_success "rename succeeded" "test_cmp expect .git/config"
+test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+'
 
 test_expect_success 'renaming empty section name is rejected' '
        test_must_fail git config --rename-section branch.zwei ""
@@ -562,7 +610,9 @@ cat >> .git/config << EOF
   [branch "zwei"] a = 1 [branch "vier"]
 EOF
 
-test_expect_success "remove section" "git config --remove-section branch.zwei"
+test_expect_success 'remove section' '
+       git config --remove-section branch.zwei
+'
 
 cat > expect << EOF
 # Hallo
@@ -571,8 +621,9 @@ cat > expect << EOF
 weird
 EOF
 
-test_expect_success "section was removed properly" \
-       "test_cmp expect .git/config"
+test_expect_success 'section was removed properly' '
+       test_cmp expect .git/config
+'
 
 cat > expect << EOF
 [gitcvs]
@@ -583,7 +634,6 @@ cat > expect << EOF
 EOF
 
 test_expect_success 'section ending' '
-
        rm -f .git/config &&
        git config gitcvs.enabled true &&
        git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
@@ -593,30 +643,25 @@ test_expect_success 'section ending' '
 '
 
 test_expect_success numbers '
-
        git config kilo.gram 1k &&
        git config mega.ton 1m &&
-       k=$(git config --int --get kilo.gram) &&
-       test z1024 = "z$k" &&
-       m=$(git config --int --get mega.ton) &&
-       test z1048576 = "z$m"
+       echo 1024 >expect &&
+       echo 1048576 >>expect &&
+       git config --int --get kilo.gram >actual &&
+       git config --int --get mega.ton >>actual &&
+       test_cmp expect actual
 '
 
-cat > expect <<EOF
-fatal: bad config value for 'aninvalid.unit' in .git/config
-EOF
-
 test_expect_success 'invalid unit' '
-
        git config aninvalid.unit "1auto" &&
-       s=$(git config aninvalid.unit) &&
-       test "z1auto" = "z$s" &&
-       if git config --int --get aninvalid.unit 2>actual
-       then
-               echo config should have failed
-               false
-       fi &&
-       cmp actual expect
+       echo 1auto >expect &&
+       git config aninvalid.unit >actual &&
+       test_cmp expect actual &&
+       cat > expect <<-\EOF
+       fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
+       EOF
+       test_must_fail git config --int --get aninvalid.unit 2>actual &&
+       test_cmp actual expect
 '
 
 cat > expect << EOF
@@ -646,7 +691,7 @@ test_expect_success bool '
            git config --bool --get bool.true$i >>result
            git config --bool --get bool.false$i >>result
         done &&
-       cmp expect result'
+       test_cmp expect result'
 
 test_expect_success 'invalid bool (--get)' '
 
@@ -680,7 +725,7 @@ test_expect_success 'set --bool' '
        git config --bool bool.false2 "" &&
        git config --bool bool.false3 nO &&
        git config --bool bool.false4 FALSE &&
-       cmp expect .git/config'
+       test_cmp expect .git/config'
 
 cat > expect <<\EOF
 [int]
@@ -695,39 +740,37 @@ test_expect_success 'set --int' '
        git config --int int.val1 01 &&
        git config --int int.val2 -1 &&
        git config --int int.val3 5m &&
-       cmp expect .git/config'
+       test_cmp expect .git/config
+'
 
-cat >expect <<\EOF
-[bool]
-       true1 = true
+test_expect_success 'get --bool-or-int' '
+       cat >.git/config <<-\EOF &&
+       [bool]
+       true1
        true2 = true
-       false1 = false
-       false2 = false
-[int]
+       false = false
+       [int]
        int1 = 0
        int2 = 1
        int3 = -1
-EOF
-
-test_expect_success 'get --bool-or-int' '
-       rm -f .git/config &&
-       (
-               echo "[bool]"
-               echo true1
-               echo true2 = true
-               echo false = false
-               echo "[int]"
-               echo int1 = 0
-               echo int2 = 1
-               echo int3 = -1
-       ) >>.git/config &&
-       test $(git config --bool-or-int bool.true1) = true &&
-       test $(git config --bool-or-int bool.true2) = true &&
-       test $(git config --bool-or-int bool.false) = false &&
-       test $(git config --bool-or-int int.int1) = 0 &&
-       test $(git config --bool-or-int int.int2) = 1 &&
-       test $(git config --bool-or-int int.int3) = -1
-
+       EOF
+       cat >expect <<-\EOF &&
+       true
+       true
+       false
+       0
+       1
+       -1
+       EOF
+       {
+               git config --bool-or-int bool.true1 &&
+               git config --bool-or-int bool.true2 &&
+               git config --bool-or-int bool.false &&
+               git config --bool-or-int int.int1 &&
+               git config --bool-or-int int.int2 &&
+               git config --bool-or-int int.int3
+       } >actual &&
+       test_cmp expect actual
 '
 
 cat >expect <<\EOF
@@ -803,6 +846,11 @@ test_expect_success NOT_MINGW 'get --path copes with unset $HOME' '
        test_cmp expect result
 '
 
+test_expect_success 'get --path barfs on boolean variable' '
+       echo "[path]bool" >.git/config &&
+       test_must_fail git config --get --path path.bool
+'
+
 cat > expect << EOF
 [quote]
        leading = " test"
@@ -844,7 +892,7 @@ EOF
 
 test_expect_success 'value continued on next line' '
        git config --list > result &&
-       cmp result expect
+       test_cmp result expect
 '
 
 cat > .git/config <<\EOF
@@ -880,11 +928,12 @@ test_expect_success '--null --get-regexp' '
 
 test_expect_success 'inner whitespace kept verbatim' '
        git config section.val "foo       bar" &&
-       test "z$(git config section.val)" = "zfoo         bar"
+       echo "foo         bar" >expect &&
+       git config section.val >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success SYMLINKS 'symlinked configuration' '
-
        ln -s notyet myconfig &&
        GIT_CONFIG=myconfig git config test.frotz nitfol &&
        test -h myconfig &&
@@ -893,9 +942,15 @@ test_expect_success SYMLINKS 'symlinked configuration' '
        GIT_CONFIG=myconfig git config test.xyzzy rezrov &&
        test -h myconfig &&
        test -f notyet &&
-       test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol &&
-       test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov
-
+       cat >expect <<-\EOF &&
+       nitfol
+       rezrov
+       EOF
+       {
+               GIT_CONFIG=notyet git config test.frotz &&
+               GIT_CONFIG=notyet git config test.xyzzy
+       } >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'nonexistent configuration' '
@@ -927,12 +982,20 @@ test_expect_success 'check split_cmdline return' "
        git commit -m 'initial commit' &&
        git config branch.master.mergeoptions 'echo \"' &&
        test_must_fail git merge master
-       "
+"
 
 test_expect_success 'git -c "key=value" support' '
-       test "z$(git -c core.name=value config core.name)" = zvalue &&
-       test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
-       test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
+       cat >expect <<-\EOF &&
+       value
+       value
+       true
+       EOF
+       {
+               git -c core.name=value config core.name &&
+               git -c foo.CamelCase=value config foo.camelcase &&
+               git -c foo.flag config --bool foo.flag
+       } >actual &&
+       test_cmp expect actual &&
        test_must_fail git -c name=value config core.name
 '
 
index 4fd83a6..e415ee0 100755 (executable)
@@ -74,6 +74,24 @@ test_expect_success "delete $m (by HEAD)" '
 '
 rm -f .git/$m
 
+test_expect_success \
+       "create $m (by HEAD)" \
+       "git update-ref HEAD $A &&
+        test $A"' = $(cat .git/'"$m"')'
+test_expect_success \
+       "pack refs" \
+       "git pack-refs --all"
+test_expect_success \
+       "move $m (by HEAD)" \
+       "git update-ref HEAD $B $A &&
+        test $B"' = $(cat .git/'"$m"')'
+test_expect_success "delete $m (by HEAD) should remove both packed and loose $m" '
+       git update-ref -d HEAD $B &&
+       ! grep "$m" .git/packed-refs &&
+       ! test -f .git/$m
+'
+rm -f .git/$m
+
 cp -f .git/HEAD .git/HEAD.orig
 test_expect_success "delete symref without dereference" '
        git update-ref --no-deref -d HEAD &&
index 2c96551..36378b0 100755 (executable)
@@ -33,4 +33,34 @@ test_expect_success 'symbolic-ref refuses bare sha1' '
 '
 reset_to_sane
 
+test_expect_success 'symbolic-ref deletes HEAD' '
+       git symbolic-ref -d HEAD &&
+       test_path_is_file .git/refs/heads/foo &&
+       test_path_is_missing .git/HEAD
+'
+reset_to_sane
+
+test_expect_success 'symbolic-ref deletes dangling HEAD' '
+       git symbolic-ref HEAD refs/heads/missing &&
+       git symbolic-ref -d HEAD &&
+       test_path_is_missing .git/refs/heads/missing &&
+       test_path_is_missing .git/HEAD
+'
+reset_to_sane
+
+test_expect_success 'symbolic-ref fails to delete missing FOO' '
+       echo "fatal: Cannot delete FOO, not a symbolic ref" >expect &&
+       test_must_fail git symbolic-ref -d FOO >actual 2>&1 &&
+       test_cmp expect actual
+'
+reset_to_sane
+
+test_expect_success 'symbolic-ref fails to delete real ref' '
+       echo "fatal: Cannot delete refs/heads/foo, not a symbolic ref" >expect &&
+       test_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 &&
+       test_path_is_file .git/refs/heads/foo &&
+       test_cmp expect actual
+'
+reset_to_sane
+
 test_done
index 1ae4d87..1a5a5f3 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 d709ecf..4969edb 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 8100537..5d68729 100755 (executable)
@@ -151,6 +151,7 @@ test_expect_success 'checkout does not warn leaving reachable commit' '
 
 cat >expect <<'EOF'
 Your branch is behind 'master' by 1 commit, and can be fast-forwarded.
+  (use "git pull" to update your local branch)
 EOF
 test_expect_success 'tracking count is accurate after orphan check' '
        reset &&
index ec35409..2a4a749 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 c8fe978..dc2f045 100755 (executable)
@@ -214,4 +214,10 @@ test_expect_success 'subdirectory ignore (l1)' '
        test_cmp expect actual
 '
 
+test_expect_success 'pattern matches prefix completely' '
+       : >expect &&
+       git ls-files -i -o --exclude "/three/a.3[abc]" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 79c8d01..80e6be3 100755 (executable)
@@ -262,6 +262,25 @@ test_expect_success 'config information was renamed, too' \
        "test $(git config branch.s.dummy) = Hello &&
         test_must_fail git config branch.s/s/dummy"
 
+test_expect_success 'deleting a symref' '
+       git branch target &&
+       git symbolic-ref refs/heads/symref refs/heads/target &&
+       echo "Deleted branch symref (was refs/heads/target)." >expect &&
+       git branch -d symref >actual &&
+       test_path_is_file .git/refs/heads/target &&
+       test_path_is_missing .git/refs/heads/symref &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'deleting a dangling symref' '
+       git symbolic-ref refs/heads/dangling-symref nowhere &&
+       test_path_is_file .git/refs/heads/dangling-symref &&
+       echo "Deleted branch dangling-symref (was nowhere)." >expect &&
+       git branch -d dangling-symref >actual &&
+       test_path_is_missing .git/refs/heads/dangling-symref &&
+       test_i18ncmp expect actual
+'
+
 test_expect_success 'renaming a symref is not allowed' \
 '
        git symbolic-ref refs/heads/master2 refs/heads/master &&
index 32fdc99..8462be1 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 34c86e5..6f489e2 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 51ca391..373aad6 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 c82f721..223b984 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 340afc7..4e7136b 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 b5fb527..7b7a89d 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 9fd28bc..37bf5f1 100755 (executable)
@@ -262,4 +262,364 @@ test_expect_success 'rm removes subdirectories recursively' '
        ! test -d dir
 '
 
+cat >expect <<EOF
+D  submod
+EOF
+
+cat >expect.modified <<EOF
+ M submod
+EOF
+
+test_expect_success 'rm removes empty submodules from work tree' '
+       mkdir submod &&
+       git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) submod &&
+       git config -f .gitmodules submodule.sub.url ./. &&
+       git config -f .gitmodules submodule.sub.path submod &&
+       git submodule init &&
+       git add .gitmodules &&
+       git commit -m "add submodule" &&
+       git rm submod &&
+       test ! -e submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm removes removed submodule from index' '
+       git reset --hard &&
+       git submodule update &&
+       rm -rf submod &&
+       git rm submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm removes work tree of unmodified submodules' '
+       git reset --hard &&
+       git submodule update &&
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm removes a submodule with a trailing /' '
+       git reset --hard &&
+       git submodule update &&
+       git rm submod/ &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm fails when given a file with a trailing /' '
+       test_must_fail git rm empty/
+'
+
+test_expect_success 'rm succeeds when given a directory with a trailing /' '
+       git rm -r frotz/
+'
+
+test_expect_success 'rm of a populated submodule with different HEAD fails unless forced' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               git checkout HEAD^
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with modifications fails unless forced' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >empty
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with untracked files fails unless forced' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >untracked
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'setup submodule conflict' '
+       git reset --hard &&
+       git submodule update &&
+       git checkout -b branch1 &&
+       echo 1 >nitfol &&
+       git add nitfol &&
+       git commit -m "added nitfol 1" &&
+       git checkout -b branch2 master &&
+       echo 2 >nitfol &&
+       git add nitfol &&
+       git commit -m "added nitfol 2" &&
+       git checkout -b conflict1 master &&
+       (cd submod &&
+               git fetch &&
+               git checkout branch1
+       ) &&
+       git add submod &&
+       git commit -m "submod 1" &&
+       git checkout -b conflict2 master &&
+       (cd submod &&
+               git checkout branch2
+       ) &&
+       git add submod &&
+       git commit -m "submod 2"
+'
+
+cat >expect.conflict <<EOF
+UU submod
+EOF
+
+test_expect_success 'rm removes work tree of unmodified conflicted submodule' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       test_must_fail git merge conflict2 &&
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with different HEAD fails unless forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               git checkout HEAD^
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >empty
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >untracked
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with a .git directory fails even when forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               rm .git &&
+               cp -R ../.git/modules/sub .git &&
+               GIT_WORK_TREE=. git config --unset core.worktree
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       test_must_fail git rm -f submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git merge --abort &&
+       rm -rf submod
+'
+
+test_expect_success 'rm of a conflicted unpopulated submodule succeeds' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       test_must_fail git merge conflict2 &&
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with a .git directory fails even when forced' '
+       git checkout -f master &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               rm .git &&
+               cp -R ../.git/modules/sub .git &&
+               GIT_WORK_TREE=. git config --unset core.worktree
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       test_must_fail git rm -f submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       rm -rf submod
+'
+
+cat >expect.deepmodified <<EOF
+ M submod/subsubmod
+EOF
+
+test_expect_success 'setup subsubmodule' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) subsubmod &&
+               git config -f .gitmodules submodule.sub.url ../. &&
+               git config -f .gitmodules submodule.sub.path subsubmod &&
+               git submodule init &&
+               git add .gitmodules &&
+               git commit -m "add subsubmodule" &&
+               git submodule update subsubmod
+       ) &&
+       git commit -a -m "added deep submodule"
+'
+
+test_expect_success 'rm recursively removes work tree of unmodified submodules' '
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with different nested HEAD fails unless forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               git checkout HEAD^
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with nested modifications fails unless forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               echo X >empty
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with nested untracked files fails unless forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               echo X >untracked
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with a nested .git directory fails even when forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               rm .git &&
+               cp -R ../../.git/modules/sub/modules/sub .git &&
+               GIT_WORK_TREE=. git config --unset core.worktree
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -d submod/subsubmod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       test_must_fail git rm -f submod &&
+       test -d submod &&
+       test -d submod/subsubmod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       rm -rf submod
+'
+
 test_done
index 3d4b1ba..0591149 100755 (executable)
@@ -32,28 +32,28 @@ test_expect_success 'prepare binary file' '
        git commit -m binbin
 '
 
-test_expect_success '--stat output after text chmod' '
-       test_chmod -x rezrov &&
-       echo " 0 files changed" >expect &&
-       git diff HEAD --stat >actual &&
-       test_i18ncmp expect actual
-'
-
-test_expect_success '--shortstat output after text chmod' '
-       git diff HEAD --shortstat >actual &&
-       test_i18ncmp expect actual
-'
-
-test_expect_success '--stat output after binary chmod' '
-       test_chmod +x binbin &&
-       echo " 0 files changed" >expect &&
-       git diff HEAD --stat >actual &&
-       test_i18ncmp expect actual
-'
-
-test_expect_success '--shortstat output after binary chmod' '
-       git diff HEAD --shortstat >actual &&
-       test_i18ncmp expect actual
-'
+test_expect_success '--stat output after text chmod' '
+#      test_chmod -x rezrov &&
+#      echo " 0 files changed" >expect &&
+#      git diff HEAD --stat >actual &&
+#      test_i18ncmp expect actual
+'
+#
+test_expect_success '--shortstat output after text chmod' '
+#      git diff HEAD --shortstat >actual &&
+#      test_i18ncmp expect actual
+'
+#
+test_expect_success '--stat output after binary chmod' '
+#      test_chmod +x binbin &&
+#      echo " 0 files changed" >expect &&
+#      git diff HEAD --stat >actual &&
+#      test_i18ncmp expect actual
+'
+#
+test_expect_success '--shortstat output after binary chmod' '
+#      git diff HEAD --shortstat >actual &&
+#      test_i18ncmp expect actual
+'
 
 test_done
index 959aa26..90fd598 100755 (executable)
@@ -110,73 +110,107 @@ test_expect_success 'replay did not screw up the log message' '
 
 test_expect_success 'extra headers' '
 
-       git config format.headers "To: R. E. Cipient <rcipient@example.com>
+       git config format.headers "To: R E Cipient <rcipient@example.com>
 " &&
-       git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
+       git config --add format.headers "Cc: S E Cipient <scipient@example.com>
 " &&
        git format-patch --stdout master..side > patch2 &&
        sed -e "/^\$/q" patch2 > hdrs2 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 &&
-       grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2
+       grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
+       grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
 
 '
 
 test_expect_success 'extra headers without newlines' '
 
-       git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
-       git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
+       git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
+       git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
        git format-patch --stdout master..side >patch3 &&
        sed -e "/^\$/q" patch3 > hdrs3 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 &&
-       grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3
+       grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
+       grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
 
 '
 
 test_expect_success 'extra headers with multiple To:s' '
 
-       git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
-       git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
+       git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
+       git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
        git format-patch --stdout master..side > patch4 &&
        sed -e "/^\$/q" patch4 > hdrs4 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 &&
-       grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4
+       grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
+       grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
 '
 
-test_expect_success 'additional command line cc' '
+test_expect_success 'additional command line cc (ascii)' '
 
-       git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
+       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
+'
+
+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 "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
+       grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5
 '
 
 test_expect_success 'command line headers' '
 
        git config --unset-all format.headers &&
-       git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
-       grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6
+       git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
+       grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
 '
 
 test_expect_success 'configuration headers and command line headers' '
 
-       git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
-       git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
-       grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 &&
-       grep "^ *S. E. Cipient <scipient@example.com>\$" patch7
+       git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
+       git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
+       grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
+       grep "^ *S E Cipient <scipient@example.com>\$" patch7
 '
 
-test_expect_success 'command line To: header' '
+test_expect_success 'command line To: header (ascii)' '
 
        git config --unset-all format.headers &&
+       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
+'
+
+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)' '
+
+       git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
+       grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
+'
+
+test_expect_success 'configuration To: header (ascii)' '
+
+       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
 '
 
-test_expect_success 'configuration To: header' '
+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)' '
+
+       git config format.to "R Ä Cipient <rcipient@example.com>" &&
+       git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
+       grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
 '
 
 # check_patch <patch>: Verify that <patch> looks like a half-sane
@@ -190,11 +224,11 @@ check_patch () {
 test_expect_success '--no-to overrides config.to' '
 
        git config --replace-all format.to \
-               "R. E. Cipient <rcipient@example.com>" &&
+               "R E Cipient <rcipient@example.com>" &&
        git format-patch --no-to --stdout master..side |
        sed -e "/^\$/q" >patch10 &&
        check_patch patch10 &&
-       ! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10
+       ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
 '
 
 test_expect_success '--no-to and --to replaces config.to' '
@@ -212,21 +246,21 @@ test_expect_success '--no-to and --to replaces config.to' '
 test_expect_success '--no-cc overrides config.cc' '
 
        git config --replace-all format.cc \
-               "C. E. Cipient <rcipient@example.com>" &&
+               "C E Cipient <rcipient@example.com>" &&
        git format-patch --no-cc --stdout master..side |
        sed -e "/^\$/q" >patch12 &&
        check_patch patch12 &&
-       ! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12
+       ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
 '
 
 test_expect_success '--no-add-header overrides config.headers' '
 
        git config --replace-all format.headers \
-               "Header1: B. E. Cipient <rcipient@example.com>" &&
+               "Header1: B E Cipient <rcipient@example.com>" &&
        git format-patch --no-add-header --stdout master..side |
        sed -e "/^\$/q" >patch13 &&
        check_patch patch13 &&
-       ! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13
+       ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
 '
 
 test_expect_success 'multiple files' '
@@ -616,8 +650,19 @@ test_expect_success 'format-patch --in-reply-to' '
 '
 
 test_expect_success 'format-patch --signoff' '
-       git format-patch -1 --signoff --stdout |
-       grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
+       git format-patch -1 --signoff --stdout >out &&
+       grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out
+'
+
+test_expect_success 'format-patch --notes --signoff' '
+       git notes --ref test add -m "test message" HEAD &&
+       git format-patch -1 --signoff --stdout --notes=test >out &&
+       # Three dashes must come after S-o-b
+       ! sed "/^Signed-off-by: /q" out | grep "test message" &&
+       sed "1,/^Signed-off-by: /d" out | grep "test message" &&
+       # Notes message must come after three dashes
+       ! sed "/^---$/q" out | grep "test message" &&
+       sed "1,/^---$/d" out | grep "test message"
 '
 
 echo "fatal: --name-only does not make sense" > expect.name-only
@@ -752,16 +797,14 @@ M64=$M8$M8$M8$M8$M8$M8$M8$M8
 M512=$M64$M64$M64$M64$M64$M64$M64$M64
 cat >expect <<'EOF'
 Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 EOF
-test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+test_expect_success 'format-patch wraps extremely long subject (ascii)' '
        echo content >>file &&
        git add file &&
        git commit -m "$M512" &&
@@ -774,30 +817,31 @@ M8="föö bar "
 M64=$M8$M8$M8$M8$M8$M8$M8$M8
 M512=$M64$M64$M64$M64$M64$M64$M64$M64
 cat >expect <<'EOF'
-Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 EOF
-test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
        rm -rf patches/ &&
        echo content >>file &&
        git add file &&
@@ -807,52 +851,80 @@ test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
        test_cmp expect subject
 '
 
-M8="foo_bar_"
-M64=$M8$M8$M8$M8$M8$M8$M8$M8
-cat >expect <<EOF
-From: $M64
- <foobar@foo.bar>
-EOF
-test_expect_success 'format-patch wraps non-quotable headers' '
-       rm -rf patches/ &&
-       echo content >>file &&
-       git add file &&
-       git commit -mfoo --author "$M64 <foobar@foo.bar>" &&
-       git format-patch --stdout -1 >patch &&
-       sed -n "/^From: /p; /^ /p; /^$/q" <patch >from &&
-       test_cmp expect from
-'
-
 check_author() {
        echo content >>file &&
        git add file &&
        GIT_AUTHOR_NAME=$1 git commit -m author-check &&
        git format-patch --stdout -1 >patch &&
-       grep ^From: patch >actual &&
+       sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
        test_cmp expect actual
 }
 
 cat >expect <<'EOF'
 From: "Foo B. Bar" <author@example.com>
 EOF
-test_expect_success 'format-patch quotes dot in headers' '
+test_expect_success 'format-patch quotes dot in from-headers' '
        check_author "Foo B. Bar"
 '
 
 cat >expect <<'EOF'
 From: "Foo \"The Baz\" Bar" <author@example.com>
 EOF
-test_expect_success 'format-patch quotes double-quote in headers' '
+test_expect_success 'format-patch quotes double-quote in from-headers' '
        check_author "Foo \"The Baz\" Bar"
 '
 
 cat >expect <<'EOF'
-From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com>
+From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
+EOF
+test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
+       check_author "Föo Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
 EOF
-test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' '
+test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
        check_author "Föo B. Bar"
 '
 
+cat >expect <<EOF
+From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
+ <author@example.com>
+EOF
+test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
+       check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
+'
+
+cat >expect <<'EOF'
+From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
+ Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
+ Bar Foo Bar Foo Bar Foo Bar <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
+       check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
+cat >expect <<'EOF'
+From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
+ Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
+ Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
+       check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
+ =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
+ =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
+ =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
+ =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
+       check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
 cat >expect <<'EOF'
 Subject: header with . in it
 EOF
index eebb1ee..53ec330 100755 (executable)
@@ -84,6 +84,30 @@ test_expect_success 'status -v produces text' '
        git reset --soft HEAD@{1}
 '
 
+test_expect_success 'grep-diff (-G) operates on textconv data (add)' '
+       echo one >expect &&
+       git log --root --format=%s -G0 >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'grep-diff (-G) operates on textconv data (modification)' '
+       echo two >expect &&
+       git log --root --format=%s -G1 >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'pickaxe (-S) operates on textconv data (add)' '
+       echo one >expect &&
+       git log --root --format=%s -S0 >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'pickaxe (-S) operates on textconv data (modification)' '
+       echo two >expect &&
+       git log --root --format=%s -S1 >actual &&
+       test_cmp expect actual
+'
+
 cat >expect.stat <<'EOF'
  file | Bin 2 -> 4 bytes
  1 file changed, 0 insertions(+), 0 deletions(-)
index 6c01d0c..32d4a60 100755 (executable)
@@ -11,18 +11,18 @@ This test tries to verify the sanity of the --submodule option of git diff.
 . ./test-lib.sh
 
 add_file () {
-       sm=$1
-       shift
-       owd=$(pwd)
-       cd "$sm"
-       for name; do
-               echo "$name" > "$name" &&
-               git add "$name" &&
-               test_tick &&
-               git commit -m "Add $name"
-       done >/dev/null
-       git rev-parse --verify HEAD | cut -c1-7
-       cd "$owd"
+       (
+               cd "$1" &&
+               shift &&
+               for name
+               do
+                       echo "$name" >"$name" &&
+                       git add "$name" &&
+                       test_tick &&
+                       git commit -m "Add $name" || exit
+               done >/dev/null &&
+               git rev-parse --short --verify HEAD
+       )
 }
 commit_file () {
        test_tick &&
@@ -33,92 +33,133 @@ test_create_repo sm1 &&
 add_file . foo >/dev/null
 
 head1=$(add_file sm1 foo1 foo2)
+fullhead1=$(cd sm1; git rev-parse --verify HEAD)
 
-test_expect_success 'added submodule' "
+test_expect_success 'added submodule' '
        git add sm1 &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 0000000...$head1 (new submodule)
-EOF
+       Submodule sm1 0000000...$head1 (new submodule)
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'added submodule, set diff.submodule' '
+       git config diff.submodule log &&
+       git add sm1 &&
+       git diff --cached >actual &&
+       cat >expected <<-EOF &&
+       Submodule sm1 0000000...$head1 (new submodule)
+       EOF
+       git config --unset diff.submodule &&
+       test_cmp expected actual
+'
+
+test_expect_success '--submodule=short overrides diff.submodule' '
+       test_config diff.submodule log &&
+       git add sm1 &&
+       git diff --submodule=short --cached >actual &&
+       cat >expected <<-EOF &&
+       diff --git a/sm1 b/sm1
+       new file mode 160000
+       index 0000000..$head1
+       --- /dev/null
+       +++ b/sm1
+       @@ -0,0 +1 @@
+       +Subproject commit $fullhead1
+       EOF
        test_cmp expected actual
-"
+'
+
+test_expect_success 'diff.submodule does not affect plumbing' '
+       test_config diff.submodule log &&
+       git diff-index -p HEAD >actual &&
+       cat >expected <<-EOF &&
+       diff --git a/sm1 b/sm1
+       new file mode 160000
+       index 0000000..$head1
+       --- /dev/null
+       +++ b/sm1
+       @@ -0,0 +1 @@
+       +Subproject commit $fullhead1
+       EOF
+       test_cmp expected actual
+'
 
 commit_file sm1 &&
 head2=$(add_file sm1 foo3)
 
-test_expect_success 'modified submodule(forward)' "
+test_expect_success 'modified submodule(forward)' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head1..$head2:
-  > Add foo3
-EOF
+       Submodule sm1 $head1..$head2:
+         > Add foo3
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule(forward)' "
+test_expect_success 'modified submodule(forward)' '
        git diff --submodule=log >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head1..$head2:
-  > Add foo3
-EOF
+       Submodule sm1 $head1..$head2:
+         > Add foo3
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule(forward) --submodule' "
+test_expect_success 'modified submodule(forward) --submodule' '
        git diff --submodule >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head1..$head2:
-  > Add foo3
-EOF
+       Submodule sm1 $head1..$head2:
+         > Add foo3
+       EOF
        test_cmp expected actual
-"
+'
 
-fullhead1=$(cd sm1; git rev-list --max-count=1 $head1)
-fullhead2=$(cd sm1; git rev-list --max-count=1 $head2)
-test_expect_success 'modified submodule(forward) --submodule=short' "
+fullhead2=$(cd sm1; git rev-parse --verify HEAD)
+test_expect_success 'modified submodule(forward) --submodule=short' '
        git diff --submodule=short >actual &&
        cat >expected <<-EOF &&
-diff --git a/sm1 b/sm1
-index $head1..$head2 160000
---- a/sm1
-+++ b/sm1
-@@ -1 +1 @@
--Subproject commit $fullhead1
-+Subproject commit $fullhead2
-EOF
+       diff --git a/sm1 b/sm1
+       index $head1..$head2 160000
+       --- a/sm1
+       +++ b/sm1
+       @@ -1 +1 @@
+       -Subproject commit $fullhead1
+       +Subproject commit $fullhead2
+       EOF
        test_cmp expected actual
-"
+'
 
 commit_file sm1 &&
 head3=$(
        cd sm1 &&
        git reset --hard HEAD~2 >/dev/null &&
-       git rev-parse --verify HEAD | cut -c1-7
+       git rev-parse --short --verify HEAD
 )
 
-test_expect_success 'modified submodule(backward)' "
+test_expect_success 'modified submodule(backward)' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head2..$head3 (rewind):
-  < Add foo3
-  < Add foo2
-EOF
+       Submodule sm1 $head2..$head3 (rewind):
+         < Add foo3
+         < Add foo2
+       EOF
        test_cmp expected actual
-"
+'
 
-head4=$(add_file sm1 foo4 foo5) &&
-head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
-test_expect_success 'modified submodule(backward and forward)' "
+head4=$(add_file sm1 foo4 foo5)
+test_expect_success 'modified submodule(backward and forward)' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head2...$head4:
-  > Add foo5
-  > Add foo4
-  < Add foo3
-  < Add foo2
-EOF
+       Submodule sm1 $head2...$head4:
+         > Add foo5
+         > Add foo4
+         < Add foo3
+         < Add foo2
+       EOF
        test_cmp expected actual
-"
+'
 
 commit_file sm1 &&
 mv sm1 sm1-bak &&
@@ -128,319 +169,319 @@ git add sm1 &&
 rm -f sm1 &&
 mv sm1-bak sm1
 
-test_expect_success 'typechanged submodule(submodule->blob), --cached' "
+test_expect_success 'typechanged submodule(submodule->blob), --cached' '
        git diff --submodule=log --cached >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 41fbea9...0000000 (submodule deleted)
-diff --git a/sm1 b/sm1
-new file mode 100644
-index 0000000..9da5fb8
---- /dev/null
-+++ b/sm1
-@@ -0,0 +1 @@
-+sm1
-EOF
+       Submodule sm1 $head4...0000000 (submodule deleted)
+       diff --git a/sm1 b/sm1
+       new file mode 100644
+       index 0000000..$head5
+       --- /dev/null
+       +++ b/sm1
+       @@ -0,0 +1 @@
+       +sm1
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'typechanged submodule(submodule->blob)' "
+test_expect_success 'typechanged submodule(submodule->blob)' '
        git diff --submodule=log >actual &&
        cat >expected <<-EOF &&
-diff --git a/sm1 b/sm1
-deleted file mode 100644
-index 9da5fb8..0000000
---- a/sm1
-+++ /dev/null
-@@ -1 +0,0 @@
--sm1
-Submodule sm1 0000000...$head4 (new submodule)
-EOF
+       diff --git a/sm1 b/sm1
+       deleted file mode 100644
+       index $head5..0000000
+       --- a/sm1
+       +++ /dev/null
+       @@ -1 +0,0 @@
+       -sm1
+       Submodule sm1 0000000...$head4 (new submodule)
+       EOF
        test_cmp expected actual
-"
+'
 
 rm -rf sm1 &&
 git checkout-index sm1
-test_expect_success 'typechanged submodule(submodule->blob)' "
+test_expect_success 'typechanged submodule(submodule->blob)' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head4...0000000 (submodule deleted)
-diff --git a/sm1 b/sm1
-new file mode 100644
-index 0000000..$head5
---- /dev/null
-+++ b/sm1
-@@ -0,0 +1 @@
-+sm1
-EOF
+       Submodule sm1 $head4...0000000 (submodule deleted)
+       diff --git a/sm1 b/sm1
+       new file mode 100644
+       index 0000000..$head5
+       --- /dev/null
+       +++ b/sm1
+       @@ -0,0 +1 @@
+       +sm1
+       EOF
        test_cmp expected actual
-"
+'
 
 rm -f sm1 &&
 test_create_repo sm1 &&
 head6=$(add_file sm1 foo6 foo7)
-fullhead6=$(cd sm1; git rev-list --max-count=1 $head6)
-test_expect_success 'nonexistent commit' "
+fullhead6=$(cd sm1; git rev-parse --verify HEAD)
+test_expect_success 'nonexistent commit' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head4...$head6 (commits not present)
-EOF
+       Submodule sm1 $head4...$head6 (commits not present)
+       EOF
        test_cmp expected actual
-"
+'
 
 commit_file
-test_expect_success 'typechanged submodule(blob->submodule)' "
+test_expect_success 'typechanged submodule(blob->submodule)' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-diff --git a/sm1 b/sm1
-deleted file mode 100644
-index $head5..0000000
---- a/sm1
-+++ /dev/null
-@@ -1 +0,0 @@
--sm1
-Submodule sm1 0000000...$head6 (new submodule)
-EOF
+       diff --git a/sm1 b/sm1
+       deleted file mode 100644
+       index $head5..0000000
+       --- a/sm1
+       +++ /dev/null
+       @@ -1 +0,0 @@
+       -sm1
+       Submodule sm1 0000000...$head6 (new submodule)
+       EOF
        test_cmp expected actual
-"
+'
 
 commit_file sm1 &&
-test_expect_success 'submodule is up to date' "
+test_expect_success 'submodule is up to date' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-EOF
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'submodule contains untracked content' "
+test_expect_success 'submodule contains untracked content' '
        echo new > sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains untracked content
-EOF
+       Submodule sm1 contains untracked content
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'submodule contains untracked content (untracked ignored)' "
+test_expect_success 'submodule contains untracked content (untracked ignored)' '
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'submodule contains untracked content (dirty ignored)' "
+test_expect_success 'submodule contains untracked content (dirty ignored)' '
        git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'submodule contains untracked content (all ignored)' "
+test_expect_success 'submodule contains untracked content (all ignored)' '
        git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'submodule contains untracked and modifed content' "
+test_expect_success 'submodule contains untracked and modifed content' '
        echo new > sm1/foo6 &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains untracked content
-Submodule sm1 contains modified content
-EOF
+       Submodule sm1 contains untracked content
+       Submodule sm1 contains modified content
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' "
+test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' '
        echo new > sm1/foo6 &&
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains modified content
-EOF
+       Submodule sm1 contains modified content
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' "
+test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' '
        echo new > sm1/foo6 &&
        git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'submodule contains untracked and modifed content (all ignored)' "
+test_expect_success 'submodule contains untracked and modifed content (all ignored)' '
        echo new > sm1/foo6 &&
        git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'submodule contains modifed content' "
+test_expect_success 'submodule contains modifed content' '
        rm -f sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains modified content
-EOF
+       Submodule sm1 contains modified content
+       EOF
        test_cmp expected actual
-"
+'
 
 (cd sm1; git commit -mchange foo6 >/dev/null) &&
-head8=$(cd sm1; git rev-parse --verify HEAD | cut -c1-7) &&
-test_expect_success 'submodule is modified' "
+head8=$(cd sm1; git rev-parse --short --verify HEAD) &&
+test_expect_success 'submodule is modified' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked content' "
+test_expect_success 'modified submodule contains untracked content' '
        echo new > sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains untracked content
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 contains untracked content
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked content (untracked ignored)' "
+test_expect_success 'modified submodule contains untracked content (untracked ignored)' '
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked content (dirty ignored)' "
+test_expect_success 'modified submodule contains untracked content (dirty ignored)' '
        git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked content (all ignored)' "
+test_expect_success 'modified submodule contains untracked content (all ignored)' '
        git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked and modifed content' "
+test_expect_success 'modified submodule contains untracked and modifed content' '
        echo modification >> sm1/foo6 &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains untracked content
-Submodule sm1 contains modified content
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 contains untracked content
+       Submodule sm1 contains modified content
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' "
+test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' '
        echo modification >> sm1/foo6 &&
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains modified content
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 contains modified content
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' "
+test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' '
        echo modification >> sm1/foo6 &&
        git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' "
+test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' '
        echo modification >> sm1/foo6 &&
        git diff-index -p --ignore-submodules --submodule=log HEAD >actual &&
        ! test -s actual
-"
+'
 
-test_expect_success 'modified submodule contains modifed content' "
+test_expect_success 'modified submodule contains modifed content' '
        rm -f sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 contains modified content
-Submodule sm1 $head6..$head8:
-  > change
-EOF
+       Submodule sm1 contains modified content
+       Submodule sm1 $head6..$head8:
+         > change
+       EOF
        test_cmp expected actual
-"
+'
 
 rm -rf sm1
-test_expect_success 'deleted submodule' "
+test_expect_success 'deleted submodule' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6...0000000 (submodule deleted)
-EOF
+       Submodule sm1 $head6...0000000 (submodule deleted)
+       EOF
        test_cmp expected actual
-"
+'
 
 test_create_repo sm2 &&
 head7=$(add_file sm2 foo8 foo9) &&
 git add sm2
 
-test_expect_success 'multiple submodules' "
+test_expect_success 'multiple submodules' '
        git diff-index -p --submodule=log HEAD >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6...0000000 (submodule deleted)
-Submodule sm2 0000000...$head7 (new submodule)
-EOF
+       Submodule sm1 $head6...0000000 (submodule deleted)
+       Submodule sm2 0000000...$head7 (new submodule)
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'path filter' "
+test_expect_success 'path filter' '
        git diff-index -p --submodule=log HEAD sm2 >actual &&
        cat >expected <<-EOF &&
-Submodule sm2 0000000...$head7 (new submodule)
-EOF
+       Submodule sm2 0000000...$head7 (new submodule)
+       EOF
        test_cmp expected actual
-"
+'
 
 commit_file sm2
-test_expect_success 'given commit' "
+test_expect_success 'given commit' '
        git diff-index -p --submodule=log HEAD^ >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6...0000000 (submodule deleted)
-Submodule sm2 0000000...$head7 (new submodule)
-EOF
+       Submodule sm1 $head6...0000000 (submodule deleted)
+       Submodule sm2 0000000...$head7 (new submodule)
+       EOF
        test_cmp expected actual
-"
+'
 
-test_expect_success 'given commit --submodule' "
+test_expect_success 'given commit --submodule' '
        git diff-index -p --submodule HEAD^ >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6...0000000 (submodule deleted)
-Submodule sm2 0000000...$head7 (new submodule)
-EOF
+       Submodule sm1 $head6...0000000 (submodule deleted)
+       Submodule sm2 0000000...$head7 (new submodule)
+       EOF
        test_cmp expected actual
-"
+'
 
-fullhead7=$(cd sm2; git rev-list --max-count=1 $head7)
+fullhead7=$(cd sm2; git rev-parse --verify HEAD)
 
-test_expect_success 'given commit --submodule=short' "
+test_expect_success 'given commit --submodule=short' '
        git diff-index -p --submodule=short HEAD^ >actual &&
        cat >expected <<-EOF &&
-diff --git a/sm1 b/sm1
-deleted file mode 160000
-index $head6..0000000
---- a/sm1
-+++ /dev/null
-@@ -1 +0,0 @@
--Subproject commit $fullhead6
-diff --git a/sm2 b/sm2
-new file mode 160000
-index 0000000..$head7
---- /dev/null
-+++ b/sm2
-@@ -0,0 +1 @@
-+Subproject commit $fullhead7
-EOF
-       test_cmp expected actual
-"
+       diff --git a/sm1 b/sm1
+       deleted file mode 160000
+       index $head6..0000000
+       --- a/sm1
+       +++ /dev/null
+       @@ -1 +0,0 @@
+       -Subproject commit $fullhead6
+       diff --git a/sm2 b/sm2
+       new file mode 160000
+       index 0000000..$head7
+       --- /dev/null
+       +++ b/sm2
+       @@ -0,0 +1 @@
+       +Subproject commit $fullhead7
+       EOF
+       test_cmp expected actual
+'
 
 test_expect_success 'setup .git file for sm2' '
        (cd sm2 &&
@@ -452,9 +493,9 @@ test_expect_success 'setup .git file for sm2' '
 test_expect_success 'diff --submodule with .git file' '
        git diff --submodule HEAD^ >actual &&
        cat >expected <<-EOF &&
-Submodule sm1 $head6...0000000 (submodule deleted)
-Submodule sm2 0000000...$head7 (new submodule)
-EOF
+       Submodule sm1 $head6...0000000 (submodule deleted)
+       Submodule sm2 0000000...$head7 (new submodule)
+       EOF
        test_cmp expected actual
 '
 
index b41eb61..5b594e8 100755 (executable)
@@ -4,19 +4,62 @@
 test_description='diff --stat-count'
 . ./test-lib.sh
 
-test_expect_success setup '
+test_expect_success 'setup' '
        >a &&
        >b &&
        >c &&
        >d &&
        git add a b c d &&
-       chmod +x c d &&
+       git commit -m initial
+'
+
+test_expect_success 'mode-only change show as a 0-line change' '
+       git reset --hard &&
+       test_chmod +x b d &&
+       echo a >a &&
+       echo c >c &&
+       cat >expect <<-\EOF
+        a | 1 +
+        b | 0
+        ...
+        4 files changed, 2 insertions(+)
+       EOF
+       git diff --stat --stat-count=2 HEAD >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'binary changes do not count in lines' '
+       git reset --hard &&
+       echo a >a &&
+       echo c >c &&
+       cat "$TEST_DIRECTORY"/test-binary-1.png >d &&
+       cat >expect <<-\EOF
+        a | 1 +
+        c | 1 +
+        ...
+        3 files changed, 2 insertions(+)
+       EOF
+       git diff --stat --stat-count=2 >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'exclude unmerged entries from total file count' '
+       git reset --hard &&
        echo a >a &&
        echo b >b &&
+       git ls-files -s a >x &&
+       git rm -f d &&
+       for stage in 1 2 3
+       do
+               sed -e "s/ 0    a/ $stage       d/" x
+       done |
+       git update-index --index-info &&
+       echo d >d &&
        cat >expect <<-\EOF
         a | 1 +
         b | 1 +
-        2 files changed, 2 insertions(+)
+        ...
+        3 files changed, 3 insertions(+)
        EOF
        git diff --stat --stat-count=2 >actual &&
        test_i18ncmp expect actual
diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh
new file mode 100755 (executable)
index 0000000..97172b4
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Mozilla Foundation
+#
+
+test_description='diff.context configuration'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       cat >template <<-\EOF &&
+       firstline
+       b
+       c
+       d
+       e
+       f
+       preline
+       TARGET
+       postline
+       i
+       j
+       k
+       l
+       m
+       n
+       EOF
+       sed "/TARGET/d" >x <template &&
+       git update-index --add x &&
+       git commit -m initial &&
+
+       sed "s/TARGET/ADDED/" >x <template &&
+       git update-index --add x &&
+       git commit -m next &&
+
+       sed "s/TARGET/MODIFIED/" >x <template
+'
+
+test_expect_success 'the default number of context lines is 3' '
+       git diff >output &&
+       ! grep "^ d" output &&
+       grep "^ e" output &&
+       grep "^ j" output &&
+       ! grep "^ k" output
+'
+
+test_expect_success 'diff.context honored by "log"' '
+       git log -1 -p >output &&
+       ! grep firstline output &&
+       git config diff.context 8 &&
+       git log -1 -p >output &&
+       grep "^ firstline" output
+'
+
+test_expect_success 'The -U option overrides diff.context' '
+       git config diff.context 8 &&
+       git log -U4 -1 >output &&
+       ! grep "^ firstline" output
+'
+
+test_expect_success 'diff.context honored by "diff"' '
+       git config diff.context 8 &&
+       git diff >output &&
+       grep "^ firstline" output
+'
+
+test_expect_success 'plumbing not affected' '
+       git config diff.context 8 &&
+       git diff-files -p >output &&
+       ! grep "^ firstline" output
+'
+
+test_expect_success 'non-integer config parsing' '
+       git config diff.context no &&
+       test_must_fail git diff 2>output &&
+       test_i18ngrep "bad config value" output
+'
+
+test_expect_success 'negative integer config parsing' '
+       git config diff.context -1 &&
+       test_must_fail git diff 2>output &&
+       test_i18ngrep "bad config file" output
+'
+
+test_expect_success '-U0 is valid, so is diff.context=0' '
+       git config diff.context 0 &&
+       git diff >output &&
+       grep "^-ADDED" output &&
+       grep "^+MODIFIED" output
+'
+
+test_done
index 6872ba1..5493500 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 924ba53..fa686b8 100755 (executable)
@@ -72,9 +72,9 @@ cat > expect << EOF
   commit.
 EOF
 
-test_expect_success 'format %w(12,1,2)' '
+test_expect_success 'format %w(11,1,2)' '
 
-       git log -2 --format="%w(12,1,2)This is the %s commit." > actual &&
+       git log -2 --format="%w(11,1,2)This is the %s commit." > actual &&
        test_cmp expect actual
 '
 
@@ -230,6 +230,12 @@ test_expect_success 'log --grep -i' '
        test_cmp expect actual
 '
 
+test_expect_success 'log -F -E --grep=<ere> uses ere' '
+       echo second >expect &&
+       git log -1 --pretty="tformat:%s" -F -E --grep=s.c.nd >actual &&
+       test_cmp expect actual
+'
+
 cat > expect <<EOF
 * Second
 * sixth
@@ -274,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 2c45de7..98a43d4 100755 (executable)
@@ -85,7 +85,7 @@ test_expect_success 'NUL termination' '
 
 test_expect_success 'NUL separation with --stat' '
        stat0_part=$(git diff --stat HEAD^ HEAD) &&
-       stat1_part=$(git diff --stat --root HEAD^) &&
+       stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
        printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected &&
        git log -z --stat --pretty="format:%s" >actual &&
        test_i18ncmp expected actual
@@ -93,7 +93,7 @@ test_expect_success 'NUL separation with --stat' '
 
 test_expect_failure 'NUL termination with --stat' '
        stat0_part=$(git diff --stat HEAD^ HEAD) &&
-       stat1_part=$(git diff --stat --root HEAD^) &&
+       stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
        printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected &&
        git log -z --stat --pretty="tformat:%s" >actual &&
        test_i18ncmp expected actual
index 46c3fe7..d0b2a45 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 ecf00ed..e7c240f 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,62 +180,12 @@ 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 5060879..c5cd2e3 100755 (executable)
@@ -130,6 +130,21 @@ test_expect_success 'clone from auth-only-for-push repository' '
        test_cmp expect actual
 '
 
+test_expect_success 'clone from auth-only-for-objects repository' '
+       echo two >expect &&
+       set_askpass user@host &&
+       git clone --bare "$HTTPD_URL/auth-fetch/smart/repo.git" half-auth &&
+       expect_askpass both user@host &&
+       git --git-dir=half-auth log -1 --format=%s >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'no-op half-auth fetch does not require a password' '
+       set_askpass wrong &&
+       git --git-dir=half-auth fetch &&
+       expect_askpass none
+'
+
 test_expect_success 'disable dumb http on server' '
        git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
                config http.getanyfile false
index ee06d28..4435693 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 72e28ee..3e0e15f 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' '
index 5c87f28..decdc33 100755 (executable)
@@ -140,6 +140,17 @@ test_expect_success '"git replace" replacing' '
      test "$HASH2" = "$(git replace)"
 '
 
+test_expect_success '"git replace" resolves sha1' '
+     SHORTHASH2=$(git rev-parse --short=8 $HASH2) &&
+     git replace -d $SHORTHASH2 &&
+     git replace $SHORTHASH2 $R &&
+     git show $HASH2 | grep "O Thor" &&
+     test_must_fail git replace $HASH2 $R &&
+     git replace -f $HASH2 $R &&
+     test_must_fail git replace -f &&
+     test "$HASH2" = "$(git replace)"
+'
+
 # This creates a side branch where the bug in H2
 # does not appear because P2 is created by applying
 # H2 and squashing H5 into it.
index 4d13e10..1e7a209 100755 (executable)
@@ -167,10 +167,11 @@ test_expect_success 'author information is preserved' '
        test_tick &&
        GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips &&
        git branch preserved-author &&
-       git filter-branch -f --msg-filter "cat; \
+       (sane_unset GIT_AUTHOR_NAME &&
+        git filter-branch -f --msg-filter "cat; \
                        test \$GIT_COMMIT != $(git rev-parse master) || \
                        echo Hallo" \
-               preserved-author &&
+               preserved-author) &&
        test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l)
 '
 
index 5189446..f5a79b1 100755 (executable)
@@ -1066,12 +1066,12 @@ test_expect_success GPG \
 '
 
 # usage with rfc1991 signatures
-echo "rfc1991" > gpghome/gpg.conf
 get_tag_header rfc1991-signed-tag $commit commit $time >expect
 echo "RFC1991 signed tag" >>expect
 echo '-----BEGIN PGP MESSAGE-----' >>expect
 test_expect_success GPG \
        'creating a signed tag with rfc1991' '
+       echo "rfc1991" >gpghome/gpg.conf &&
        git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
        get_tag_msg rfc1991-signed-tag >actual &&
        test_cmp expect actual
@@ -1085,6 +1085,7 @@ chmod +x fakeeditor
 
 test_expect_success GPG \
        'reediting a signed tag body omits signature' '
+       echo "rfc1991" >gpghome/gpg.conf &&
        echo "RFC1991 signed tag" >expect &&
        GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
        test_cmp expect actual
@@ -1092,11 +1093,13 @@ test_expect_success GPG \
 
 test_expect_success GPG \
        'verifying rfc1991 signature' '
+       echo "rfc1991" >gpghome/gpg.conf &&
        git tag -v rfc1991-signed-tag
 '
 
 test_expect_success GPG \
        'list tag with rfc1991 signature' '
+       echo "rfc1991" >gpghome/gpg.conf &&
        echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
        git tag -l -n1 rfc1991-signed-tag >actual &&
        test_cmp expect actual &&
index fd6410f..26f8319 100755 (executable)
@@ -111,6 +111,28 @@ test_expect_success 'grep respects binary diff attribute' '
        test_cmp expect actual
 '
 
+test_expect_success 'grep --cached respects binary diff attribute' '
+       git grep --cached text t >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'grep --cached respects binary diff attribute (2)' '
+       git add .gitattributes &&
+       rm .gitattributes &&
+       git grep --cached text t >actual &&
+       test_when_finished "git rm --cached .gitattributes" &&
+       test_when_finished "git checkout .gitattributes" &&
+       test_cmp expect actual
+'
+
+test_expect_success 'grep revision respects binary diff attribute' '
+       git commit -m new &&
+       echo "Binary file HEAD:t matches" >expect &&
+       git grep text HEAD -- t >actual &&
+       test_when_finished "git reset HEAD^" &&
+       test_cmp expect actual
+'
+
 test_expect_success 'grep respects not-binary diff attribute' '
        echo binQary | q_to_nul >b &&
        git add b &&
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 5397037..de7d453 100755 (executable)
@@ -681,4 +681,79 @@ test_expect_success 'moving the superproject does not break submodules' '
        )
 '
 
+test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' '
+       (
+               cd addtest2 &&
+               (
+                       cd repo &&
+                       echo "$submodurl/repo" >expect &&
+                       git config remote.origin.url >actual &&
+                       test_cmp expect actual &&
+                       echo "gitdir: ../.git/modules/repo" >expect &&
+                       test_cmp expect .git
+               ) &&
+               rm -rf repo &&
+               git rm repo &&
+               git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual &&
+               test ! -s actual &&
+               echo "gitdir: ../.git/modules/submod" >expect &&
+               test_cmp expect submod/.git &&
+               (
+                       cd repo &&
+                       echo "$submodurl/bare.git" >expect &&
+                       git config remote.origin.url >actual &&
+                       test_cmp expect actual &&
+                       echo "gitdir: ../.git/modules/repo_new" >expect &&
+                       test_cmp expect .git
+               ) &&
+               echo "repo" >expect &&
+               git config -f .gitmodules submodule.repo.path >actual &&
+               test_cmp expect actual &&
+               git config -f .gitmodules submodule.repo_new.path >actual &&
+               test_cmp expect actual&&
+               echo "$submodurl/repo" >expect &&
+               git config -f .gitmodules submodule.repo.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/bare.git" >expect &&
+               git config -f .gitmodules submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/repo" >expect &&
+               git config submodule.repo.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/bare.git" >expect &&
+               git config submodule.repo_new.url >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'submodule add with an existing name fails unless forced' '
+       (
+               cd addtest2 &&
+               rm -rf repo &&
+               git rm repo &&
+               test_must_fail git submodule add -q --name repo_new "$submodurl/repo.git" repo &&
+               test ! -d repo &&
+               echo "repo" >expect &&
+               git config -f .gitmodules submodule.repo_new.path >actual &&
+               test_cmp expect actual&&
+               echo "$submodurl/bare.git" >expect &&
+               git config -f .gitmodules submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/bare.git" >expect &&
+               git config submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               git submodule add -f -q --name repo_new "$submodurl/repo.git" repo &&
+               test -d repo &&
+               echo "repo" >expect &&
+               git config -f .gitmodules submodule.repo_new.path >actual &&
+               test_cmp expect actual&&
+               echo "$submodurl/repo.git" >expect &&
+               git config -f .gitmodules submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/repo.git" >expect &&
+               git config submodule.repo_new.url >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done
index f919c8d..8e32f19 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 524d5c1..94e26c4 100755 (executable)
@@ -17,18 +17,25 @@ test_expect_success setup '
        git commit -m upstream &&
        git clone . super &&
        git clone super submodule &&
+       (cd submodule &&
+        git submodule add ../submodule sub-submodule &&
+        test_tick &&
+        git commit -m "sub-submodule"
+       ) &&
        (cd super &&
         git submodule add ../submodule submodule &&
         test_tick &&
         git commit -m "submodule"
        ) &&
        git clone super super-clone &&
-       (cd super-clone && git submodule update --init) &&
+       (cd super-clone && git submodule update --init --recursive) &&
        git clone super empty-clone &&
        (cd empty-clone && git submodule init) &&
        git clone super top-only-clone &&
        git clone super relative-clone &&
-       (cd relative-clone && git submodule update --init)
+       (cd relative-clone && git submodule update --init --recursive) &&
+       git clone super recursive-clone &&
+       (cd recursive-clone && git submodule update --init --recursive)
 '
 
 test_expect_success 'change submodule' '
@@ -46,6 +53,11 @@ test_expect_success 'change submodule url' '
         git pull
        ) &&
        mv submodule moved-submodule &&
+       (cd moved-submodule &&
+        git config -f .gitmodules submodule.sub-submodule.url ../moved-submodule &&
+        test_tick &&
+        git commit -a -m moved-sub-submodule
+       ) &&
        (cd super &&
         git config -f .gitmodules submodule.submodule.url ../moved-submodule &&
         test_tick &&
@@ -61,6 +73,9 @@ test_expect_success '"git submodule sync" should update submodule URLs' '
        test -d "$(cd super-clone/submodule &&
         git config remote.origin.url
        )" &&
+       test ! -d "$(cd super-clone/submodule/sub-submodule &&
+        git config remote.origin.url
+       )" &&
        (cd super-clone/submodule &&
         git checkout master &&
         git pull
@@ -70,6 +85,25 @@ test_expect_success '"git submodule sync" should update submodule URLs' '
        )
 '
 
+test_expect_success '"git submodule sync --recursive" should update all submodule URLs' '
+       (cd super-clone &&
+        (cd submodule &&
+         git pull --no-recurse-submodules
+        ) &&
+        git submodule sync --recursive
+       ) &&
+       test -d "$(cd super-clone/submodule &&
+        git config remote.origin.url
+       )" &&
+       test -d "$(cd super-clone/submodule/sub-submodule &&
+        git config remote.origin.url
+       )" &&
+       (cd super-clone/submodule/sub-submodule &&
+        git checkout master &&
+        git pull
+       )
+'
+
 test_expect_success '"git submodule sync" should update known submodule URLs' '
        (cd empty-clone &&
         git pull &&
@@ -107,6 +141,23 @@ test_expect_success '"git submodule sync" handles origin URL of the form foo/bar
         #actual foo/submodule
         test "$(git config remote.origin.url)" = "../foo/submodule"
        )
+       (cd submodule/sub-submodule &&
+        test "$(git config remote.origin.url)" != "../../foo/submodule"
+       )
+       )
+'
+
+test_expect_success '"git submodule sync --recursive" propagates changes in origin' '
+       (cd recursive-clone &&
+        git remote set-url origin foo/bar &&
+        git submodule sync --recursive &&
+       (cd submodule &&
+        #actual foo/submodule
+        test "$(git config remote.origin.url)" = "../foo/submodule"
+       )
+       (cd submodule/sub-submodule &&
+        test "$(git config remote.origin.url)" = "../../foo/submodule"
+       )
        )
 '
 
index 1542653..feaec6c 100755 (executable)
@@ -627,7 +627,7 @@ test_expect_success 'submodule add properly re-creates deeper level submodules'
        (cd super &&
         git reset --hard master &&
         rm -rf deeper/ &&
-        git submodule add ../submodule deeper/submodule
+        git submodule add --force ../submodule deeper/submodule
        )
 '
 
index 9b69fe2..107b4b7 100755 (executable)
@@ -226,14 +226,14 @@ test_expect_success 'test "status --recursive"' '
        test_cmp expect actual
 '
 
-sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2
+sed -e "/nested2 /s/.*/+$nested2sha1 nested1\/nested2 (file2~1)/;/sub[1-3]/d" < expect > expect2
 mv -f expect2 expect
 
 test_expect_success 'ensure "status --cached --recursive" preserves the --cached flag' '
        (
                cd clone3 &&
                (
-                       cd nested1 &&
+                       cd nested1/nested2 &&
                        test_commit file2
                ) &&
                git submodule status --cached --recursive -- nested1 > ../actual
index deb187e..1a5cb69 100755 (executable)
@@ -243,16 +243,6 @@ test_expect_success 'message shows author when it is not equal to committer' '
          .git/COMMIT_EDITMSG
 '
 
-test_expect_success 'setup auto-ident prerequisite' '
-       if (sane_unset GIT_COMMITTER_EMAIL &&
-           sane_unset GIT_COMMITTER_NAME &&
-           git var GIT_COMMITTER_IDENT); then
-               test_set_prereq AUTOIDENT
-       else
-               test_set_prereq NOAUTOIDENT
-       fi
-'
-
 test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
 
        echo >>negative &&
@@ -271,7 +261,7 @@ echo editor started > "$(pwd)/.git/result"
 exit 0
 EOF
 
-test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' '
+test_expect_success !AUTOIDENT 'do not fire editor when committer is bogus' '
        >.git/result
        >expect &&
 
index 5b4b694..3573751 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 0351228..97d6f4c 100755 (executable)
@@ -191,17 +191,44 @@ test_expect_success $PREREQ 'Show all headers' '
 
 test_expect_success $PREREQ 'Prompting works' '
        clean_fake_sendmail &&
-       (echo "Example <from@example.com>"
-        echo "to@example.com"
+       (echo "to@example.com"
         echo ""
        ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches \
                2>errors &&
-               grep "^From: Example <from@example.com>\$" msgtxt1 &&
+               grep "^From: A U Thor <author@example.com>\$" msgtxt1 &&
                grep "^To: to@example.com\$" msgtxt1
 '
 
+test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' '
+       clean_fake_sendmail &&
+       (sane_unset GIT_AUTHOR_NAME &&
+       sane_unset GIT_AUTHOR_EMAIL &&
+       sane_unset GIT_COMMITTER_NAME &&
+       sane_unset GIT_COMMITTER_EMAIL &&
+       GIT_SEND_EMAIL_NOTTY=1 git send-email \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               --to=to@example.com \
+               $patches </dev/null 2>errors
+       )
+'
+
+test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' '
+       clean_fake_sendmail &&
+       (sane_unset GIT_AUTHOR_NAME &&
+       sane_unset GIT_AUTHOR_EMAIL &&
+       sane_unset GIT_COMMITTER_NAME &&
+       sane_unset GIT_COMMITTER_EMAIL &&
+       GIT_SEND_EMAIL_NOTTY=1 && export GIT_SEND_EMAIL_NOTTY &&
+       test_must_fail git send-email \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               --to=to@example.com \
+               $patches </dev/null 2>errors &&
+       test_i18ngrep "tell me who you are" errors
+       )
+'
+
 test_expect_success $PREREQ 'tocmd works' '
        clean_fake_sendmail &&
        cp $patches tocmd.patch &&
@@ -854,6 +881,75 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' '
        grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
 '
 
+test_expect_success $PREREQ 'sendemail.composeencoding works' '
+       clean_fake_sendmail &&
+       git config sendemail.composeencoding iso-8859-1 &&
+       (echo "#!$SHELL_PATH" &&
+        echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         git send-email \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose-encoding works' '
+       clean_fake_sendmail &&
+       (echo "#!$SHELL_PATH" &&
+        echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         git send-email \
+         --compose-encoding iso-8859-1 \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' '
+       clean_fake_sendmail &&
+       git config sendemail.composeencoding iso-8859-1 &&
+       (echo "#!$SHELL_PATH" &&
+        echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         git send-email \
+         --compose-encoding iso-8859-2 \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' '
+       clean_fake_sendmail &&
+         GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+         git send-email \
+         --compose-encoding iso-8859-2 \
+         --compose --subject utf8-sübjëct \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^fake edit" msgtxt1 &&
+       grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
+'
+
 test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
        echo master > master &&
        git add master &&
@@ -1074,6 +1170,23 @@ EOF
 '
 
 test_expect_success $PREREQ 'setup expect' '
+cat >expected <<EOF
+Subject: subject goes here
+EOF
+'
+
+test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
+       clean_fake_sendmail &&
+       echo bogus |
+       git send-email --from=author@example.com --to=nobody@example.com \
+                       --smtp-server="$(pwd)/fake.sendmail" \
+                       --8bit-encoding=UTF-8 \
+                       email-using-8bit >stdout &&
+       grep "Subject" msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
 cat >content-type-decl <<EOF
 MIME-Version: 1.0
 Content-Type: text/plain; charset=UTF-8
diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
new file mode 100755 (executable)
index 0000000..2d2f016
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+test_description='tests remote-svn'
+
+. ./test-lib.sh
+
+MARKSPATH=.git/info/fast-import/remote-svn
+
+if ! test_have_prereq PYTHON
+then
+       skip_all='skipping remote-svn tests, python not available'
+       test_done
+fi
+
+# 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 &&
+       git init &&
+       #git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
+       # let's reuse an exisiting dump file!?
+       git remote add svnsim testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump
+       git remote add svnfile testsvn::file://$TEST_DIRECTORY/t9154/svn.dump
+}
+
+if test -e "$GIT_BUILD_DIR/git-remote-testsvn"
+then
+       test_set_prereq REMOTE_SVN
+fi
+
+test_debug '
+       git --version
+       type git
+       type svnrdump
+'
+
+test_expect_success REMOTE_SVN 'simple fetch' '
+       init_git &&
+       git fetch svnsim &&
+       test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+       cp .git/refs/remotes/svnsim/master master.good
+'
+
+test_debug '
+       cat .git/refs/svn/svnsim/master
+       cat .git/refs/remotes/svnsim/master
+'
+
+test_expect_success REMOTE_SVN 'repeated fetch, nothing shall change' '
+       git fetch svnsim &&
+       test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_expect_success REMOTE_SVN 'fetch from a file:// url gives the same result' '
+       git fetch svnfile
+'
+
+test_expect_failure REMOTE_SVN 'the sha1 differ because the git-svn-id line in the commit msg contains the url' '
+       test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master
+'
+
+test_expect_success REMOTE_SVN 'mark-file regeneration' '
+       # filter out any other marks, that can not be regenerated. Only up to 3 digit revisions are allowed here
+       grep ":[0-9]\{1,3\} " $MARKSPATH/svnsim.marks > $MARKSPATH/svnsim.marks.old &&
+       rm $MARKSPATH/svnsim.marks &&
+       git fetch svnsim &&
+       test_cmp $MARKSPATH/svnsim.marks.old $MARKSPATH/svnsim.marks
+'
+
+test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' '
+       export SVNRMAX=3 &&
+       init_git &&
+       git fetch svnsim &&
+       test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+       unset SVNRMAX &&
+       git fetch svnsim &&
+       test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_debug 'git branch -a'
+
+test_done
index b59be9a..3fb3368 100755 (executable)
@@ -19,14 +19,15 @@ then
     test_done
 fi
 
-CVSROOT=$PWD/cvsroot
+CVSROOT=$PWD/tmpcvsroot
 CVSWORK=$PWD/cvswork
 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 806623e..9502f24 100755 (executable)
@@ -400,7 +400,7 @@ cat >expected.C <<EOF
 Line 0
 =======
 LINE 0
->>>>>>> merge.3
+>>>>>>> merge.1.3
 EOF
 
 for i in 1 2 3 4 5 6 7 8
@@ -505,6 +505,76 @@ test_expect_success 'cvs co -c (shows module database)' '
 '
 
 #------------
+# CVS LOG
+#------------
+
+# Known issues with git-cvsserver current log output:
+#  - Hard coded "lines: +2 -3" placeholder, instead of real numbers.
+#  - CVS normally does not internally add a blank first line
+#    nor a last line with nothing but a space to log messages.
+#  - The latest cvs 1.12.x server sends +0000 timezone (with some hidden "MT"
+#    tagging in the protocol), and if cvs 1.12.x client sees the MT tags,
+#    it converts to local time zone.  git-cvsserver doesn't do the +0000
+#    or the MT tags...
+#  - The latest 1.12.x releases add a "commitid:" field on to the end of the
+#    "date:" line (after "lines:").  Maybe we could stick git's commit id
+#    in it?  Or does CVS expect a certain number of bits (too few for
+#    a full sha1)?
+#
+# Given the above, expect the following test to break if git-cvsserver's
+# log output is improved.  The test is just to ensure it doesn't
+# accidentally get worse.
+
+sed -e 's/^x//' -e 's/SP$/ /' > "$WORKDIR/expect" <<EOF
+x
+xRCS file: $WORKDIR/gitcvs.git/master/merge,v
+xWorking file: merge
+xhead: 1.4
+xbranch:
+xlocks: strict
+xaccess list:
+xsymbolic names:
+xkeyword substitution: kv
+xtotal revisions: 4;   selected revisions: 4
+xdescription:
+x----------------------------
+xrevision 1.4
+xdate: __DATE__;  author: author;  state: Exp;  lines: +2 -3
+x
+xMerge test (no-op)
+xSP
+x----------------------------
+xrevision 1.3
+xdate: __DATE__;  author: author;  state: Exp;  lines: +2 -3
+x
+xMerge test (conflict)
+xSP
+x----------------------------
+xrevision 1.2
+xdate: __DATE__;  author: author;  state: Exp;  lines: +2 -3
+x
+xMerge test (merge)
+xSP
+x----------------------------
+xrevision 1.1
+xdate: __DATE__;  author: author;  state: Exp;  lines: +2 -3
+x
+xMerge test (pre-merge)
+xSP
+x=============================================================================
+EOF
+expectStat="$?"
+
+cd "$WORKDIR"
+test_expect_success 'cvs log' '
+    cd cvswork &&
+    test x"$expectStat" = x"0" &&
+    GIT_CONFIG="$git_config" cvs log merge >../out &&
+    sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual &&
+    test_cmp ../expect ../actual
+'
+
+#------------
 # CVS ANNOTATE
 #------------
 
index ff6d6fb..1c5bc84 100755 (executable)
@@ -38,6 +38,25 @@ not_present() {
     fi
 }
 
+check_status_options() {
+    (cd "$1" &&
+    GIT_CONFIG="$git_config" cvs -Q status "$2" > "${WORKDIR}/status.out" 2>&1
+    )
+    if [ x"$?" != x"0" ] ; then
+       echo "Error from cvs status: $1 $2" >> "${WORKDIR}/marked.log"
+       return 1;
+    fi
+    got="$(sed -n -e 's/^[     ]*Sticky Options:[      ]*//p' "${WORKDIR}/status.out")"
+    expect="$3"
+    if [ x"$expect" = x"" ] ; then
+       expect="(none)"
+    fi
+    test x"$got" = x"$expect"
+    stat=$?
+    echo "cvs status: $1 $2 $stat '$3' '$got'" >> "${WORKDIR}/marked.log"
+    return $stat
+}
+
 cvs >/dev/null 2>&1
 if test $? -ne 1
 then
@@ -233,6 +252,22 @@ test_expect_success 'cvs co another copy (guess)' '
     marked_as cvswork2/subdir newfile.c ""
 '
 
+test_expect_success 'cvs status - sticky options' '
+    check_status_options cvswork2 textfile.c "" &&
+    check_status_options cvswork2 binfile.bin -kb &&
+    check_status_options cvswork2 .gitattributes "" &&
+    check_status_options cvswork2 mixedUp.c -kb &&
+    check_status_options cvswork2 multiline.c -kb &&
+    check_status_options cvswork2 multilineTxt.c "" &&
+    check_status_options cvswork2/subdir withCr.bin -kb &&
+    check_status_options cvswork2 subdir/withCr.bin -kb &&
+    check_status_options cvswork2/subdir file.h "" &&
+    check_status_options cvswork2 subdir/file.h "" &&
+    check_status_options cvswork2/subdir unspecified.other "" &&
+    check_status_options cvswork2/subdir newfile.bin "" &&
+    check_status_options cvswork2/subdir newfile.c ""
+'
+
 test_expect_success 'add text (guess)' '
     (cd cvswork &&
     echo "simpleText" > simpleText.c &&
index 731e64c..86dfee2 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 '
@@ -185,5 +185,20 @@ test_expect_success 'forks: project_index lists all projects (incl. forks)' '
        test_cmp expected actual
 '
 
+xss() {
+       echo >&2 "Checking $1..." &&
+       gitweb_run "$1" &&
+       if grep "$TAG" gitweb.body; then
+               echo >&2 "xss: $TAG should have been quoted in output"
+               return 1
+       fi
+       return 0
+}
+
+test_expect_success 'xss checks' '
+       TAG="<magic-xss-tag>" &&
+       xss "a=rss&p=$TAG" &&
+       xss "a=rss&p=foo.git&f=$TAG"
+'
 
 test_done
diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh
new file mode 100755 (executable)
index 0000000..1fd5142
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='git cvsimport timestamps'
+. ./lib-cvs.sh
+
+setup_cvs_test_repository t9604
+
+test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' '
+
+       TZ=CST6CDT git cvsimport -p"-x" -C module-1 module &&
+       git cvsimport -p"-x" -C module-1 module &&
+       (
+               cd module-1 &&
+               git log --format="%s %ai"
+       ) >actual-1 &&
+       cat >expect-1 <<-EOF &&
+       Rev 16 2006-10-29 07:00:01 +0000
+       Rev 15 2006-10-29 06:59:59 +0000
+       Rev 14 2006-04-02 08:00:01 +0000
+       Rev 13 2006-04-02 07:59:59 +0000
+       Rev 12 2005-12-01 00:00:00 +0000
+       Rev 11 2005-11-01 00:00:00 +0000
+       Rev 10 2005-10-01 00:00:00 +0000
+       Rev  9 2005-09-01 00:00:00 +0000
+       Rev  8 2005-08-01 00:00:00 +0000
+       Rev  7 2005-07-01 00:00:00 +0000
+       Rev  6 2005-06-01 00:00:00 +0000
+       Rev  5 2005-05-01 00:00:00 +0000
+       Rev  4 2005-04-01 00:00:00 +0000
+       Rev  3 2005-03-01 00:00:00 +0000
+       Rev  2 2005-02-01 00:00:00 +0000
+       Rev  1 2005-01-01 00:00:00 +0000
+       EOF
+       test_cmp actual-1 expect-1
+'
+
+test_expect_success 'check timestamps with author-specific timezones' '
+
+       cat >cvs-authors <<-EOF &&
+       user1=User One <user1@domain.org>
+       user2=User Two <user2@domain.org> CST6CDT
+       user3=User Three <user3@domain.org> EST5EDT
+       user4=User Four <user4@domain.org> MST7MDT
+       EOF
+       git cvsimport -p"-x" -A cvs-authors -C module-2 module &&
+       (
+               cd module-2 &&
+               git log --format="%s %ai %an"
+       ) >actual-2 &&
+       cat >expect-2 <<-EOF &&
+       Rev 16 2006-10-29 01:00:01 -0600 User Two
+       Rev 15 2006-10-29 01:59:59 -0500 User Two
+       Rev 14 2006-04-02 03:00:01 -0500 User Two
+       Rev 13 2006-04-02 01:59:59 -0600 User Two
+       Rev 12 2005-11-30 17:00:00 -0700 User Four
+       Rev 11 2005-10-31 19:00:00 -0500 User Three
+       Rev 10 2005-09-30 19:00:00 -0500 User Two
+       Rev  9 2005-09-01 00:00:00 +0000 User One
+       Rev  8 2005-07-31 18:00:00 -0600 User Four
+       Rev  7 2005-06-30 20:00:00 -0400 User Three
+       Rev  6 2005-05-31 19:00:00 -0500 User Two
+       Rev  5 2005-05-01 00:00:00 +0000 User One
+       Rev  4 2005-03-31 17:00:00 -0700 User Four
+       Rev  3 2005-02-28 19:00:00 -0500 User Three
+       Rev  2 2005-01-31 18:00:00 -0600 User Two
+       Rev  1 2005-01-01 00:00:00 +0000 User One
+       EOF
+       test_cmp actual-2 expect-2
+'
+
+test_done
diff --git a/t/t9604/cvsroot/.gitattributes b/t/t9604/cvsroot/.gitattributes
new file mode 100644 (file)
index 0000000..562b12e
--- /dev/null
@@ -0,0 +1 @@
+* -whitespace
diff --git a/t/t9604/cvsroot/CVSROOT/.gitignore b/t/t9604/cvsroot/CVSROOT/.gitignore
new file mode 100644 (file)
index 0000000..3bb9b34
--- /dev/null
@@ -0,0 +1,2 @@
+history
+val-tags
diff --git a/t/t9604/cvsroot/module/a,v b/t/t9604/cvsroot/module/a,v
new file mode 100644 (file)
index 0000000..80658c3
--- /dev/null
@@ -0,0 +1,264 @@
+head   1.16;
+access;
+symbols;
+locks; strict;
+comment        @# @;
+
+
+1.16
+date   2006.10.29.07.00.01;    author user2;   state Exp;
+branches;
+next   1.15;
+
+1.15
+date   2006.10.29.06.59.59;    author user2;   state Exp;
+branches;
+next   1.14;
+
+1.14
+date   2006.04.02.08.00.01;    author user2;   state Exp;
+branches;
+next   1.13;
+
+1.13
+date   2006.04.02.07.59.59;    author user2;   state Exp;
+branches;
+next   1.12;
+
+1.12
+date   2005.12.01.00.00.00;    author user4;   state Exp;
+branches;
+next   1.11;
+
+1.11
+date   2005.11.01.00.00.00;    author user3;   state Exp;
+branches;
+next   1.10;
+
+1.10
+date   2005.10.01.00.00.00;    author user2;   state Exp;
+branches;
+next   1.9;
+
+1.9
+date   2005.09.01.00.00.00;    author user1;   state Exp;
+branches;
+next   1.8;
+
+1.8
+date   2005.08.01.00.00.00;    author user4;   state Exp;
+branches;
+next   1.7;
+
+1.7
+date   2005.07.01.00.00.00;    author user3;   state Exp;
+branches;
+next   1.6;
+
+1.6
+date   2005.06.01.00.00.00;    author user2;   state Exp;
+branches;
+next   1.5;
+
+1.5
+date   2005.05.01.00.00.00;    author user1;   state Exp;
+branches;
+next   1.4;
+
+1.4
+date   2005.04.01.00.00.00;    author user4;   state Exp;
+branches;
+next   1.3;
+
+1.3
+date   2005.03.01.00.00.00;    author user3;   state Exp;
+branches;
+next   1.2;
+
+1.2
+date   2005.02.01.00.00.00;    author user2;   state Exp;
+branches;
+next   1.1;
+
+1.1
+date   2005.01.01.00.00.00;    author user1;   state Exp;
+branches;
+next   ;
+
+
+desc
+@@
+
+
+1.16
+log
+@Rev 16
+@
+text
+@Rev 16
+@
+
+
+1.15
+log
+@Rev 15
+@
+text
+@d1 1
+a1 1
+Rev 15
+@
+
+
+1.14
+log
+@Rev 14
+@
+text
+@d1 1
+a1 1
+Rev 14
+@
+
+
+1.13
+log
+@Rev 13
+@
+text
+@d1 1
+a1 1
+Rev 13
+@
+
+
+1.12
+log
+@Rev 12
+@
+text
+@d1 1
+a1 1
+Rev 12
+@
+
+
+1.11
+log
+@Rev 11
+@
+text
+@d1 1
+a1 1
+Rev 11
+@
+
+
+1.10
+log
+@Rev 10
+@
+text
+@d1 1
+a1 1
+Rev 10
+@
+
+
+1.9
+log
+@Rev  9
+@
+text
+@d1 1
+a1 1
+Rev 9
+@
+
+
+1.8
+log
+@Rev  8
+@
+text
+@d1 1
+a1 1
+Rev 8
+@
+
+
+1.7
+log
+@Rev  7
+@
+text
+@d1 1
+a1 1
+Rev 7
+@
+
+
+1.6
+log
+@Rev  6
+@
+text
+@d1 1
+a1 1
+Rev 6
+@
+
+
+1.5
+log
+@Rev  5
+@
+text
+@d1 1
+a1 1
+Rev 5
+@
+
+
+1.4
+log
+@Rev  4
+@
+text
+@d1 1
+a1 1
+Rev 4
+@
+
+
+1.3
+log
+@Rev  3
+@
+text
+@d1 1
+a1 1
+Rev 3
+@
+
+
+1.2
+log
+@Rev  2
+@
+text
+@d1 1
+a1 1
+Rev 2
+@
+
+
+1.1
+log
+@Rev  1
+@
+text
+@d1 1
+a1 1
+Rev 1
+@
index 3b9b484..0d4e366 100755 (executable)
@@ -46,8 +46,7 @@ is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color");
 # Save and restore STDERR; we will probably extract this into a
 # "dies_ok" method and possibly move the STDERR handling to Git.pm.
 open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR;
-eval { $r->config("test.dupstring") };
-ok($@, "config: duplicate entry in scalar context fails");
+is($r->config("test.dupstring"), "value2", "config: multivar");
 eval { $r->config_bool("test.boolother") };
 ok($@, "config_bool: non-boolean values fail");
 open STDERR, ">&", $tmpstderr or die "cannot restore STDERR";
index b7ad716..8c59796 100755 (executable)
@@ -143,7 +143,18 @@ test_expect_success 'exit when p4 fails to produce marshaled output' '
        ! test_i18ngrep Traceback errs
 '
 
-test_expect_success 'clone bare' '
+# Hide a file from p4d, make sure we catch its complaint.  This won't fail in
+# p4 changes, files, or describe; just in p4 print.  If P4CLIENT is unset, the
+# message will include "Librarian checkout".
+test_expect_success 'exit gracefully for p4 server errors' '
+       test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" &&
+       mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden &&
+       test_when_finished cleanup_git &&
+       test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err &&
+       test_i18ngrep "Error from p4 print" err
+'
+
+test_expect_success 'clone --bare should make a bare repository' '
        rm -rf "$git" &&
        git p4 clone --dest="$git" --bare //depot &&
        test_when_finished cleanup_git &&
@@ -172,6 +183,18 @@ test_expect_success 'initial import time from top change time' '
        )
 '
 
+test_expect_success 'unresolvable host in P4PORT should display error' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               P4PORT=nosuchhost:65537 &&
+               export P4PORT &&
+               test_expect_code 1 git p4 sync >out 2>err &&
+               grep "connect to nosuchhost" err
+       )
+'
+
 test_expect_success 'kill p4d' '
        kill_p4d
 '
index 21924df..aae1a3f 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 fe30ad8..34fbc90 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 &&
@@ -155,6 +157,25 @@ test_expect_success 'cleanup after failure' '
        )
 '
 
+# perl $File:: bug check
+test_expect_success 'ktext expansion should not expand multi-line $File::' '
+       (
+               cd "$cli" &&
+               cat >lv.pm <<-\EOF
+               my $wanted = sub { my $f = $File::Find::name;
+                                   if ( -f && $f =~ /foo/ ) {
+               EOF
+               p4 add -t ktext lv.pm &&
+               p4 submit -d "lv.pm"
+       ) &&
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               test_cmp "$cli/lv.pm" lv.pm
+       )
+'
+
 #
 # Do not scrub anything but +k or +ko files.  Sneak a change into
 # the cli file so that submit will get a conflict.  Make sure that
@@ -170,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 3bf1224..be802e0 100755 (executable)
@@ -199,6 +199,41 @@ test_expect_success 'detect copies' '
        )
 '
 
+# See if configurables can be set, and in particular if the run.move.allow
+# variable exists, which allows admins to disable the "p4 move" command.
+test_expect_success 'p4 configure command and run.move.allow are available' '
+       p4 configure show run.move.allow >out ; retval=$? &&
+       test $retval = 0 &&
+       {
+               egrep ^run.move.allow: out &&
+               test_set_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW ||
+               true
+       } || true
+'
+
+# If move can be disabled, turn it off and test p4 move handling
+test_expect_success P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW \
+                   'do not use p4 move when administratively disabled' '
+       test_when_finished "p4 configure set run.move.allow=1" &&
+       p4 configure set run.move.allow=0 &&
+       (
+               cd "$cli" &&
+               echo move-disallow-file >move-disallow-file &&
+               p4 add move-disallow-file &&
+               p4 submit -d "add move-disallow-file"
+       ) &&
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               git config git-p4.detectRenames true &&
+               git mv move-disallow-file move-disallow-file-moved &&
+               git commit -m "move move-disallow-file" &&
+               git p4 submit
+       )
+'
+
 test_expect_success 'kill p4d' '
        kill_p4d
 '
index cbd0fb6..adc1372 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.
@@ -54,105 +73,78 @@ run_completion ()
        __git_wrap__git_main && print_comp
 }
 
+# Test high-level completion
+# Arguments are:
+# 1: typed text so far (cur)
+# 2: expected completion
 test_completion ()
 {
-       test $# -gt 1 && echo "$2" > expected
-       run_completion "$@" &&
+       if test $# -gt 1
+       then
+               printf '%s\n' "$2" >expected
+       else
+               sed -e 's/Z$//' >expected
+       fi &&
+       run_completion "$1" &&
        test_cmp expected out
 }
 
-# Like test_completion, but reads expectation from stdin,
-# which is convenient when it is multiline. We also process "_" into
-# spaces to make test vectors more readable.
-test_completion_long ()
+# Test __gitcomp.
+# The first argument is the typed text so far (cur); the rest are
+# passed to __gitcomp.  Expected output comes is read from the
+# standard input, like test_completion().
+test_gitcomp ()
 {
-       tr _ " " >expected &&
-       test_completion "$1"
+       local -a COMPREPLY &&
+       sed -e 's/Z$//' >expected &&
+       cur="$1" &&
+       shift &&
+       __gitcomp "$@" &&
+       print_comp &&
+       test_cmp expected out
 }
 
-newline=$'\n'
-
 test_expect_success '__gitcomp - trailing space - options' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
+               --reset-author" <<-EOF
        --reuse-message=Z
        --reedit-message=Z
        --reset-author Z
        EOF
-       (
-               local -a COMPREPLY &&
-               cur="--re" &&
-               __gitcomp "--dry-run --reuse-message= --reedit-message=
-                               --reset-author" &&
-               IFS="$newline" &&
-               echo "${COMPREPLY[*]}" > out
-       ) &&
-       test_cmp expected out
 '
 
 test_expect_success '__gitcomp - trailing space - config keys' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_gitcomp "br" "branch. branch.autosetupmerge
+               branch.autosetuprebase browser." <<-\EOF
        branch.Z
        branch.autosetupmerge Z
        branch.autosetuprebase Z
        browser.Z
        EOF
-       (
-               local -a COMPREPLY &&
-               cur="br" &&
-               __gitcomp "branch. branch.autosetupmerge
-                               branch.autosetuprebase browser." &&
-               IFS="$newline" &&
-               echo "${COMPREPLY[*]}" > out
-       ) &&
-       test_cmp expected out
 '
 
 test_expect_success '__gitcomp - option parameter' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_gitcomp "--strategy=re" "octopus ours recursive resolve subtree" \
+               "" "re" <<-\EOF
        recursive Z
        resolve Z
        EOF
-       (
-               local -a COMPREPLY &&
-               cur="--strategy=re" &&
-               __gitcomp "octopus ours recursive resolve subtree
-                       " "" "re" &&
-               IFS="$newline" &&
-               echo "${COMPREPLY[*]}" > out
-       ) &&
-       test_cmp expected out
 '
 
 test_expect_success '__gitcomp - prefix' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_gitcomp "branch.me" "remote merge mergeoptions rebase" \
+               "branch.maint." "me" <<-\EOF
        branch.maint.merge Z
        branch.maint.mergeoptions Z
        EOF
-       (
-               local -a COMPREPLY &&
-               cur="branch.me" &&
-               __gitcomp "remote merge mergeoptions rebase
-                       " "branch.maint." "me" &&
-               IFS="$newline" &&
-               echo "${COMPREPLY[*]}" > out
-       ) &&
-       test_cmp expected out
 '
 
 test_expect_success '__gitcomp - suffix' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_gitcomp "branch.me" "master maint next pu" "branch." \
+               "ma" "." <<-\EOF
        branch.master.Z
        branch.maint.Z
        EOF
-       (
-               local -a COMPREPLY &&
-               cur="branch.me" &&
-               __gitcomp "master maint next pu
-                       " "branch." "ma" "." &&
-               IFS="$newline" &&
-               echo "${COMPREPLY[*]}" > out
-       ) &&
-       test_cmp expected out
 '
 
 test_expect_success 'basic' '
@@ -169,7 +161,7 @@ test_expect_success 'basic' '
 '
 
 test_expect_success 'double dash "git" itself' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_completion "git --" <<-\EOF
        --paginate Z
        --no-pager Z
        --git-dir=
@@ -184,11 +176,10 @@ test_expect_success 'double dash "git" itself' '
        --no-replace-objects Z
        --help Z
        EOF
-       test_completion "git --"
 '
 
 test_expect_success 'double dash "git checkout"' '
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_completion "git checkout --" <<-\EOF
        --quiet Z
        --ours Z
        --theirs Z
@@ -199,17 +190,15 @@ test_expect_success 'double dash "git checkout"' '
        --orphan Z
        --patch Z
        EOF
-       test_completion "git checkout --"
 '
 
 test_expect_success 'general options' '
        test_completion "git --ver" "--version " &&
        test_completion "git --hel" "--help " &&
-       sed -e "s/Z$//" >expected <<-\EOF &&
+       test_completion "git --exe" <<-\EOF &&
        --exec-path Z
        --exec-path=
        EOF
-       test_completion "git --exe" &&
        test_completion "git --htm" "--html-path " &&
        test_completion "git --pag" "--paginate " &&
        test_completion "git --no-p" "--no-pager " &&
@@ -226,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 " &&
@@ -237,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 &&
@@ -247,25 +240,25 @@ test_expect_success 'setup for ref completion' '
 '
 
 test_expect_success 'checkout completes ref names' '
-       test_completion_long "git checkout m" <<-\EOF
-       master_
-       mybranch_
-       mytag_
+       test_completion "git checkout m" <<-\EOF
+       master Z
+       mybranch Z
+       mytag Z
        EOF
 '
 
 test_expect_success 'show completes all refs' '
-       test_completion_long "git show m" <<-\EOF
-       master_
-       mybranch_
-       mytag_
+       test_completion "git show m" <<-\EOF
+       master Z
+       mybranch Z
+       mytag Z
        EOF
 '
 
 test_expect_success '<ref>: completes paths' '
-       test_completion_long "git show mytag:f" <<-\EOF
-       file1_
-       file2_
+       test_completion "git show mytag:f" <<-\EOF
+       file1 Z
+       file2 Z
        EOF
 '
 
@@ -273,8 +266,8 @@ test_expect_success 'complete tree filename with spaces' '
        echo content >"name with spaces" &&
        git add . &&
        git commit -m spaces &&
-       test_completion_long "git show HEAD:nam" <<-\EOF
-       name with spaces_
+       test_completion "git show HEAD:nam" <<-\EOF
+       name with spaces Z
        EOF
 '
 
@@ -282,10 +275,15 @@ test_expect_failure 'complete tree filename with metacharacters' '
        echo content >"name with \${meta}" &&
        git add . &&
        git commit -m meta &&
-       test_completion_long "git show HEAD:nam" <<-\EOF
-       name with ${meta}_
-       name with spaces_
+       test_completion "git show HEAD:nam" <<-\EOF
+       name with ${meta} Z
+       name with spaces Z
        EOF
 '
 
+test_expect_success 'send-email' '
+       test_completion "git send-email --cov" "--cover-letter " &&
+       test_completion "git send-email ma" "master "
+'
+
 test_done
index 8889ba5..fa62d01 100644 (file)
@@ -275,6 +275,15 @@ test_have_prereq () {
 
        for prerequisite
        do
+               case "$prerequisite" in
+               !*)
+                       negative_prereq=t
+                       prerequisite=${prerequisite#!}
+                       ;;
+               *)
+                       negative_prereq=
+               esac
+
                case " $lazily_tested_prereq " in
                *" $prerequisite "*)
                        ;;
@@ -294,10 +303,20 @@ test_have_prereq () {
                total_prereq=$(($total_prereq + 1))
                case "$satisfied_prereq" in
                *" $prerequisite "*)
+                       satisfied_this_prereq=t
+                       ;;
+               *)
+                       satisfied_this_prereq=
+               esac
+
+               case "$satisfied_this_prereq,$negative_prereq" in
+               t,|,t)
                        ok_prereq=$(($ok_prereq + 1))
                        ;;
                *)
-                       # Keep a list of missing prerequisites
+                       # Keep a list of missing prerequisites; restore
+                       # the negative marker if necessary.
+                       prerequisite=${negative_prereq:+!}$prerequisite
                        if test -z "$missing_prereq"
                        then
                                missing_prereq=$prerequisite
@@ -583,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 514282c..ea1e4a0 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)
@@ -230,7 +232,7 @@ else
        say_color() {
                test -z "$1" && test -n "$quiet" && return
                shift
-               echo "$*"
+               printf "%s\n" "$*"
        }
 fi
 
@@ -389,7 +391,8 @@ test_done () {
        then
                test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
                mkdir -p "$test_results_dir"
-               test_results_path="$test_results_dir/${0%.sh}-$$.counts"
+               base=${0##*/}
+               test_results_path="$test_results_dir/${base%.sh}-$$.counts"
 
                cat >>"$test_results_path" <<-EOF
                total $test_count
@@ -738,6 +741,12 @@ test_lazy_prereq UTF8_NFD_TO_NFC '
        esac
 '
 
+test_lazy_prereq AUTOIDENT '
+       sane_unset GIT_AUTHOR_NAME &&
+       sane_unset GIT_AUTHOR_EMAIL &&
+       git var GIT_AUTHOR_IDENT
+'
+
 # When the tests are run as root, permission tests will report that
 # things are writable when they shouldn't be.
 test -w / || test_set_prereq SANITY
index 10172ae..1fb373f 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 3bc20e9..0092cbf 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 4693295..00ce6c9 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 83633a2..0f2d9a4 100644 (file)
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
        if (argc == 2) {
                if (svndump_init(argv[1]))
                        return 1;
-               svndump_read(NULL);
+               svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
                svndump_deinit();
                svndump_reset();
                return 0;
index cfe0988..4713b69 100644 (file)
@@ -10,6 +10,7 @@
 #include "string-list.h"
 #include "thread-utils.h"
 #include "sigchain.h"
+#include "argv-array.h"
 
 static int debug;
 
@@ -19,6 +20,7 @@ struct helper_data {
        FILE *out;
        unsigned fetch : 1,
                import : 1,
+               bidi_import : 1,
                export : 1,
                option : 1,
                push : 1,
@@ -101,6 +103,7 @@ static void do_take_over(struct transport *transport)
 static struct child_process *get_helper(struct transport *transport)
 {
        struct helper_data *data = transport->data;
+       struct argv_array argv = ARGV_ARRAY_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct child_process *helper;
        const char **refspecs = NULL;
@@ -122,11 +125,10 @@ static struct child_process *get_helper(struct transport *transport)
        helper->in = -1;
        helper->out = -1;
        helper->err = 0;
-       helper->argv = xcalloc(4, sizeof(*helper->argv));
-       strbuf_addf(&buf, "git-remote-%s", data->name);
-       helper->argv[0] = strbuf_detach(&buf, NULL);
-       helper->argv[1] = transport->remote->name;
-       helper->argv[2] = remove_ext_force(transport->url);
+       argv_array_pushf(&argv, "git-remote-%s", data->name);
+       argv_array_push(&argv, transport->remote->name);
+       argv_array_push(&argv, remove_ext_force(transport->url));
+       helper->argv = argv_array_detach(&argv, NULL);
        helper->git_cmd = 0;
        helper->silent_exec_failure = 1;
 
@@ -178,6 +180,8 @@ static struct child_process *get_helper(struct transport *transport)
                        data->push = 1;
                else if (!strcmp(capname, "import"))
                        data->import = 1;
+               else if (!strcmp(capname, "bidi-import"))
+                       data->bidi_import = 1;
                else if (!strcmp(capname, "export"))
                        data->export = 1;
                else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
@@ -241,8 +245,7 @@ static int disconnect_helper(struct transport *transport)
                close(data->helper->out);
                fclose(data->out);
                res = finish_command(data->helper);
-               free((char *)data->helper->argv[0]);
-               free(data->helper->argv);
+               argv_array_free_detached(data->helper->argv);
                free(data->helper);
                data->helper = NULL;
        }
@@ -376,14 +379,23 @@ static int fetch_with_fetch(struct transport *transport,
 static int get_importer(struct transport *transport, struct child_process *fastimport)
 {
        struct child_process *helper = get_helper(transport);
+       struct helper_data *data = transport->data;
+       struct argv_array argv = ARGV_ARRAY_INIT;
+       int cat_blob_fd, code;
        memset(fastimport, 0, sizeof(*fastimport));
        fastimport->in = helper->out;
-       fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
-       fastimport->argv[0] = "fast-import";
-       fastimport->argv[1] = "--quiet";
+       argv_array_push(&argv, "fast-import");
+       argv_array_push(&argv, debug ? "--stats" : "--quiet");
 
+       if (data->bidi_import) {
+               cat_blob_fd = xdup(helper->in);
+               argv_array_pushf(&argv, "--cat-blob-fd=%d", cat_blob_fd);
+       }
+       fastimport->argv = argv.argv;
        fastimport->git_cmd = 1;
-       return start_command(fastimport);
+
+       code = start_command(fastimport);
+       return code;
 }
 
 static int get_exporter(struct transport *transport,
@@ -438,11 +450,17 @@ static int fetch_with_import(struct transport *transport,
        }
 
        write_constant(data->helper->in, "\n");
+       /*
+        * remote-helpers that advertise the bidi-import capability are required to
+        * buffer the complete batch of import commands until this newline before
+        * sending data to fast-import.
+        * These helpers read back data from fast-import on their stdin, which could
+        * be mixed with import commands, otherwise.
+        */
 
        if (finish_command(&fastimport))
                die("Error while running fast-import");
-       free(fastimport.argv);
-       fastimport.argv = NULL;
+       argv_array_free_detached(fastimport.argv);
 
        /*
         * The fast-import stream of a remote helper that advertises
index 9932f40..b9306ef 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;
index 3b21c4a..4a61c0c 100644 (file)
@@ -175,4 +175,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
 typedef void alternate_ref_fn(const struct ref *, void *);
 extern void for_each_alternate_ref(alternate_ref_fn, void *);
 
+struct send_pack_args;
+extern int send_pack(struct send_pack_args *args,
+                    int fd[], struct child_process *conn,
+                    struct ref *remote_refs,
+                    struct extra_have_objects *extra_have);
 #endif
index 492c7cd..3f54c02 100644 (file)
@@ -490,11 +490,11 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
 
 static int match_entry(const struct name_entry *entry, int pathlen,
                       const char *match, int matchlen,
-                      int *never_interesting)
+                      enum interesting *never_interesting)
 {
        int m = -1; /* signals that we haven't called strncmp() */
 
-       if (*never_interesting) {
+       if (*never_interesting != entry_not_interesting) {
                /*
                 * We have not seen any match that sorts later
                 * than the current path.
@@ -522,7 +522,7 @@ static int match_entry(const struct name_entry *entry, int pathlen,
                 * the variable to -1 and that is what will be
                 * returned, allowing the caller to terminate early.
                 */
-               *never_interesting = 0;
+               *never_interesting = entry_not_interesting;
        }
 
        if (pathlen > matchlen)
@@ -584,7 +584,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
 {
        int i;
        int pathlen, baselen = base->len - base_offset;
-       int never_interesting = ps->has_wildcard ?
+       enum interesting never_interesting = ps->has_wildcard ?
                entry_not_interesting : all_entries_not_interesting;
 
        if (!ps->nr) {
index 2e90ccb..6142421 100644 (file)
@@ -727,12 +727,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
                " include-tag multi_ack_detailed";
        struct object *o = lookup_unknown_object(sha1);
        const char *refname_nons = strip_namespace(refname);
-
-       if (o->type == OBJ_NONE) {
-               o->type = sha1_object_info(sha1, NULL);
-               if (o->type < 0)
-                   die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
-       }
+       unsigned char peeled[20];
 
        if (capabilities)
                packet_write(1, "%s %s%c%s%s agent=%s\n",
@@ -747,11 +742,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
                o->flags |= OUR_REF;
                nr_our_refs++;
        }
-       if (o->type == OBJ_TAG) {
-               o = deref_tag_noverify(o);
-               if (o)
-                       packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname_nons);
-       }
+       if (!peel_ref(refname, peeled))
+               packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons);
        return 0;
 }
 
diff --git a/usage.c b/usage.c
index a2a6678..8eab281 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -6,6 +6,8 @@
 #include "git-compat-util.h"
 #include "cache.h"
 
+static int dying;
+
 void vreportf(const char *prefix, const char *err, va_list params)
 {
        char msg[4096];
@@ -82,6 +84,12 @@ void NORETURN die(const char *err, ...)
 {
        va_list params;
 
+       if (dying) {
+               fputs("fatal: recursion detected in die handler\n", stderr);
+               exit(128);
+       }
+       dying = 1;
+
        va_start(params, err);
        die_routine(err, params);
        va_end(params);
@@ -94,6 +102,13 @@ void NORETURN die_errno(const char *fmt, ...)
        char str_error[256], *err;
        int i, j;
 
+       if (dying) {
+               fputs("fatal: recursion detected in die_errno handler\n",
+                       stderr);
+               exit(128);
+       }
+       dying = 1;
+
        err = strerror(errno);
        for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
                if ((str_error[j++] = err[i++]) != '%')
diff --git a/utf8.c b/utf8.c
index a544f15..a4ee665 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:
@@ -353,17 +353,17 @@ retry:
 
                c = *text;
                if (!c || isspace(c)) {
-                       if (w < width || !space) {
+                       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 @@ new_line:
        }
 }
 
-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)
@@ -423,6 +422,13 @@ int is_encoding_utf8(const char *name)
        return 0;
 }
 
+int same_encoding(const char *src, const char *dst)
+{
+       if (is_encoding_utf8(src) && is_encoding_utf8(dst))
+               return 1;
+       return !strcasecmp(src, dst);
+}
+
 /*
  * 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 3c0ae76..a214238 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -7,10 +7,11 @@ int utf8_width(const char **start, size_t *remainder_p);
 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 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 1f04697..f2b23c8 100644 (file)
@@ -3,8 +3,7 @@
  * See LICENSE for details.
  */
 
-#include "git-compat-util.h"
-#include "strbuf.h"
+#include "cache.h"
 #include "quote.h"
 #include "fast_export.h"
 #include "repo_tree.h"
@@ -68,11 +67,33 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
        putchar('\n');
 }
 
+void fast_export_begin_note(uint32_t revision, const char *author,
+               const char *log, unsigned long timestamp, const char *note_ref)
+{
+       static int firstnote = 1;
+       size_t loglen = strlen(log);
+       printf("commit %s\n", note_ref);
+       printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp);
+       printf("data %"PRIuMAX"\n", (uintmax_t)loglen);
+       fwrite(log, loglen, 1, stdout);
+       if (firstnote) {
+               if (revision > 1)
+                       printf("from %s^0", note_ref);
+               firstnote = 0;
+       }
+       fputc('\n', stdout);
+}
+
+void fast_export_note(const char *committish, const char *dataref)
+{
+       printf("N %s %s\n", dataref, committish);
+}
+
 static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
                        const struct strbuf *log,
                        const char *uuid, const char *url,
-                       unsigned long timestamp)
+                       unsigned long timestamp, const char *local_ref)
 {
        static const struct strbuf empty = STRBUF_INIT;
        if (!log)
@@ -84,7 +105,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,
        } else {
                *gitsvnline = '\0';
        }
-       printf("commit refs/heads/master\n");
+       printf("commit %s\n", local_ref);
        printf("mark :%"PRIu32"\n", revision);
        printf("committer %s <%s@%s> %ld +0000\n",
                   *author ? author : "nobody",
@@ -222,6 +243,13 @@ static long apply_delta(off_t len, struct line_buffer *input,
        return ret;
 }
 
+void fast_export_buf_to_data(const struct strbuf *data)
+{
+       printf("data %"PRIuMAX"\n", (uintmax_t)data->len);
+       fwrite(data->buf, data->len, 1, stdout);
+       fputc('\n', stdout);
+}
+
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
 {
        assert(len >= 0);
index 8823aca..c8b5adb 100644 (file)
@@ -9,11 +9,15 @@ void fast_export_deinit(void);
 
 void fast_export_delete(const char *path);
 void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
+void fast_export_note(const char *committish, const char *dataref);
+void fast_export_begin_note(uint32_t revision, const char *author,
+               const char *log, unsigned long timestamp, const char *note_ref);
 void fast_export_begin_commit(uint32_t revision, const char *author,
-                       const struct strbuf *log, const char *uuid,
-                       const char *url, unsigned long timestamp);
+                       const struct strbuf *log, const char *uuid,const char *url,
+                       unsigned long timestamp, const char *local_ref);
 void fast_export_end_commit(uint32_t revision);
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);
+void fast_export_buf_to_data(const struct strbuf *data);
 void fast_export_blob_delta(uint32_t mode,
                        uint32_t old_mode, const char *old_data,
                        off_t len, struct line_buffer *input);
index 2b168ae..31d1d83 100644 (file)
@@ -48,7 +48,7 @@ static struct {
 static struct {
        uint32_t revision;
        unsigned long timestamp;
-       struct strbuf log, author;
+       struct strbuf log, author, note;
 } rev_ctx;
 
 static struct {
@@ -77,6 +77,7 @@ static void reset_rev_ctx(uint32_t revision)
        rev_ctx.timestamp = 0;
        strbuf_reset(&rev_ctx.log);
        strbuf_reset(&rev_ctx.author);
+       strbuf_reset(&rev_ctx.note);
 }
 
 static void reset_dump_ctx(const char *url)
@@ -299,22 +300,29 @@ static void handle_node(void)
                                node_ctx.text_length, &input);
 }
 
-static void begin_revision(void)
+static void begin_revision(const char *remote_ref)
 {
        if (!rev_ctx.revision)  /* revision 0 gets no git commit. */
                return;
        fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
                &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-               rev_ctx.timestamp);
+               rev_ctx.timestamp, remote_ref);
 }
 
-static void end_revision(void)
+static void end_revision(const char *note_ref)
 {
-       if (rev_ctx.revision)
+       struct strbuf mark = STRBUF_INIT;
+       if (rev_ctx.revision) {
                fast_export_end_commit(rev_ctx.revision);
+               fast_export_begin_note(rev_ctx.revision, "remote-svn",
+                               "Note created by remote-svn.", rev_ctx.timestamp, note_ref);
+               strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
+               fast_export_note(mark.buf, "inline");
+               fast_export_buf_to_data(&rev_ctx.note);
+       }
 }
 
-void svndump_read(const char *url)
+void svndump_read(const char *url, const char *local_ref, const char *notes_ref)
 {
        char *val;
        char *t;
@@ -353,11 +361,12 @@ void svndump_read(const char *url)
                        if (active_ctx == NODE_CTX)
                                handle_node();
                        if (active_ctx == REV_CTX)
-                               begin_revision();
+                               begin_revision(local_ref);
                        if (active_ctx != DUMP_CTX)
-                               end_revision();
+                               end_revision(notes_ref);
                        active_ctx = REV_CTX;
                        reset_rev_ctx(atoi(val));
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        break;
                case sizeof("Node-path"):
                        if (constcmp(t, "Node-"))
@@ -366,13 +375,15 @@ void svndump_read(const char *url)
                                if (active_ctx == NODE_CTX)
                                        handle_node();
                                if (active_ctx == REV_CTX)
-                                       begin_revision();
+                                       begin_revision(local_ref);
                                active_ctx = NODE_CTX;
                                reset_node_ctx(val);
+                               strbuf_addf(&rev_ctx.note, "%s\n", t);
                                break;
                        }
                        if (constcmp(t + strlen("Node-"), "kind"))
                                continue;
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        if (!strcmp(val, "dir"))
                                node_ctx.type = REPO_MODE_DIR;
                        else if (!strcmp(val, "file"))
@@ -383,6 +394,7 @@ void svndump_read(const char *url)
                case sizeof("Node-action"):
                        if (constcmp(t, "Node-action"))
                                continue;
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        if (!strcmp(val, "delete")) {
                                node_ctx.action = NODEACT_DELETE;
                        } else if (!strcmp(val, "add")) {
@@ -401,11 +413,13 @@ void svndump_read(const char *url)
                                continue;
                        strbuf_reset(&node_ctx.src);
                        strbuf_addstr(&node_ctx.src, val);
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        break;
                case sizeof("Node-copyfrom-rev"):
                        if (constcmp(t, "Node-copyfrom-rev"))
                                continue;
                        node_ctx.srcRev = atoi(val);
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        break;
                case sizeof("Text-content-length"):
                        if (constcmp(t, "Text") && constcmp(t, "Prop"))
@@ -463,25 +477,40 @@ void svndump_read(const char *url)
        if (active_ctx == NODE_CTX)
                handle_node();
        if (active_ctx == REV_CTX)
-               begin_revision();
+               begin_revision(local_ref);
        if (active_ctx != DUMP_CTX)
-               end_revision();
+               end_revision(notes_ref);
 }
 
-int svndump_init(const char *filename)
+static void init(int report_fd)
 {
-       if (buffer_init(&input, filename))
-               return error("cannot open %s: %s", filename, strerror(errno));
-       fast_export_init(REPORT_FILENO);
+       fast_export_init(report_fd);
        strbuf_init(&dump_ctx.uuid, 4096);
        strbuf_init(&dump_ctx.url, 4096);
        strbuf_init(&rev_ctx.log, 4096);
        strbuf_init(&rev_ctx.author, 4096);
+       strbuf_init(&rev_ctx.note, 4096);
        strbuf_init(&node_ctx.src, 4096);
        strbuf_init(&node_ctx.dst, 4096);
        reset_dump_ctx(NULL);
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
+       return;
+}
+
+int svndump_init(const char *filename)
+{
+       if (buffer_init(&input, filename))
+               return error("cannot open %s: %s", filename ? filename : "NULL", strerror(errno));
+       init(REPORT_FILENO);
+       return 0;
+}
+
+int svndump_init_fd(int in_fd, int back_fd)
+{
+       if(buffer_fdinit(&input, xdup(in_fd)))
+               return error("cannot open fd %d: %s", in_fd, strerror(errno));
+       init(xdup(back_fd));
        return 0;
 }
 
@@ -492,6 +521,8 @@ void svndump_deinit(void)
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
        strbuf_release(&rev_ctx.log);
+       strbuf_release(&rev_ctx.author);
+       strbuf_release(&rev_ctx.note);
        strbuf_release(&node_ctx.src);
        strbuf_release(&node_ctx.dst);
        if (buffer_deinit(&input))
index df9ceb0..b8eb129 100644 (file)
@@ -2,7 +2,8 @@
 #define SVNDUMP_H_
 
 int svndump_init(const char *filename);
-void svndump_read(const char *url);
+int svndump_init_fd(int in_fd, int back_fd);
+void svndump_read(const char *url, const char *local_ref, const char *notes_ref);
 void svndump_deinit(void);
 void svndump_reset(void);
 
diff --git a/version b/version
index 27f9cd3..4d9a387 100644 (file)
--- a/version
+++ b/version
@@ -1 +1 @@
-1.8.0
+1.8.1.3
index 68739aa..bac59d2 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 d45b536..960f448 100644 (file)
@@ -34,12 +34,7 @@ void maybe_flush_or_die(FILE *f, const char *desc)
                        return;
        }
        if (fflush(f)) {
-               /*
-                * On Windows, EPIPE is returned only by the first write()
-                * after the reading end has closed its handle; subsequent
-                * write()s return EINVAL.
-                */
-               if (errno == EPIPE || errno == EINVAL)
+               if (errno == EPIPE)
                        exit(0);
                die_errno("write failure on '%s'", desc);
        }
index 2a9658b..d7cfe8f 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];